From: Álvaro Fernández Rojas Date: Mon, 5 May 2025 11:01:55 +0000 (+0200) Subject: generic: 6.12: sync Realtek PHY patches with upstream X-Git-Url: http://git.openwrt.org/%22https:/collectd.org//%22/%22https:/collectd.org/%22?a=commitdiff_plain;h=81e46d2a2330b695b48296e6876796a755dcfd54;p=openwrt%2Fopenwrt.git generic: 6.12: sync Realtek PHY patches with upstream - Fix order of patches (3d483a10327f was merged before 34d5a86ff7bb). - Reorganize patch numbers now that < 6.12 patches are no longer needed. Signed-off-by: Álvaro Fernández Rojas --- diff --git a/target/linux/generic/backport-6.12/781-01-v6.13-net-phy-realtek-read-duplex-and-gbit-master-from-PHY.patch b/target/linux/generic/backport-6.12/781-01-v6.13-net-phy-realtek-read-duplex-and-gbit-master-from-PHY.patch new file mode 100644 index 0000000000..2a1726ac80 --- /dev/null +++ b/target/linux/generic/backport-6.12/781-01-v6.13-net-phy-realtek-read-duplex-and-gbit-master-from-PHY.patch @@ -0,0 +1,106 @@ +From 081c9c0265c91b8333165aa6230c20bcbc6f7cbf Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 10 Oct 2024 14:07:16 +0100 +Subject: [PATCH] net: phy: realtek: read duplex and gbit master from PHYSR + register + +The PHYSR MMD register is present and defined equally for all RTL82xx +Ethernet PHYs. +Read duplex and Gbit master bits from rtlgen_decode_speed() and rename +it to rtlgen_decode_physr(). + +Signed-off-by: Daniel Golle +Link: https://patch.msgid.link/b9a76341da851a18c985bc4774fa295babec79bb.1728565530.git.daniel@makrotopia.org +Signed-off-by: Paolo Abeni +--- + drivers/net/phy/realtek.c | 41 +++++++++++++++++++++++++++++++-------- + 1 file changed, 33 insertions(+), 8 deletions(-) + +--- a/drivers/net/phy/realtek.c ++++ b/drivers/net/phy/realtek.c +@@ -80,15 +80,18 @@ + + #define RTL822X_VND2_GANLPAR 0xa414 + +-#define RTL822X_VND2_PHYSR 0xa434 +- + #define RTL8366RB_POWER_SAVE 0x15 + #define RTL8366RB_POWER_SAVE_ON BIT(12) + + #define RTL9000A_GINMR 0x14 + #define RTL9000A_GINMR_LINK_STATUS BIT(4) + +-#define RTLGEN_SPEED_MASK 0x0630 ++#define RTL_VND2_PHYSR 0xa434 ++#define RTL_VND2_PHYSR_DUPLEX BIT(3) ++#define RTL_VND2_PHYSR_SPEEDL GENMASK(5, 4) ++#define RTL_VND2_PHYSR_SPEEDH GENMASK(10, 9) ++#define RTL_VND2_PHYSR_MASTER BIT(11) ++#define RTL_VND2_PHYSR_SPEED_MASK (RTL_VND2_PHYSR_SPEEDL | RTL_VND2_PHYSR_SPEEDH) + + #define RTL_GENERIC_PHYID 0x001cc800 + #define RTL_8211FVD_PHYID 0x001cc878 +@@ -660,9 +663,18 @@ static int rtl8366rb_config_init(struct + } + + /* get actual speed to cover the downshift case */ +-static void rtlgen_decode_speed(struct phy_device *phydev, int val) ++static void rtlgen_decode_physr(struct phy_device *phydev, int val) + { +- switch (val & RTLGEN_SPEED_MASK) { ++ /* bit 3 ++ * 0: Half Duplex ++ * 1: Full Duplex ++ */ ++ if (val & RTL_VND2_PHYSR_DUPLEX) ++ phydev->duplex = DUPLEX_FULL; ++ else ++ phydev->duplex = DUPLEX_HALF; ++ ++ switch (val & RTL_VND2_PHYSR_SPEED_MASK) { + case 0x0000: + phydev->speed = SPEED_10; + break; +@@ -684,6 +696,19 @@ static void rtlgen_decode_speed(struct p + default: + break; + } ++ ++ /* bit 11 ++ * 0: Slave Mode ++ * 1: Master Mode ++ */ ++ if (phydev->speed >= 1000) { ++ if (val & RTL_VND2_PHYSR_MASTER) ++ phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER; ++ else ++ phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE; ++ } else { ++ phydev->master_slave_state = MASTER_SLAVE_STATE_UNSUPPORTED; ++ } + } + + static int rtlgen_read_status(struct phy_device *phydev) +@@ -701,7 +726,7 @@ static int rtlgen_read_status(struct phy + if (val < 0) + return val; + +- rtlgen_decode_speed(phydev, val); ++ rtlgen_decode_physr(phydev, val); + + return 0; + } +@@ -1007,11 +1032,11 @@ static int rtl822x_c45_read_status(struc + return 0; + + /* Read actual speed from vendor register. */ +- val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_PHYSR); ++ val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL_VND2_PHYSR); + if (val < 0) + return val; + +- rtlgen_decode_speed(phydev, val); ++ rtlgen_decode_physr(phydev, val); + + return 0; + } diff --git a/target/linux/generic/backport-6.12/781-02-v6.13-net-phy-realtek-change-order-of-calls-in-C22-read_st.patch b/target/linux/generic/backport-6.12/781-02-v6.13-net-phy-realtek-change-order-of-calls-in-C22-read_st.patch new file mode 100644 index 0000000000..4341adb878 --- /dev/null +++ b/target/linux/generic/backport-6.12/781-02-v6.13-net-phy-realtek-change-order-of-calls-in-C22-read_st.patch @@ -0,0 +1,53 @@ +From 68d5cd09e8919679ce13b85950debea4b2e98e04 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 10 Oct 2024 14:07:26 +0100 +Subject: [PATCH] net: phy: realtek: change order of calls in C22 read_status() + +Always call rtlgen_read_status() first, so genphy_read_status() which +is called by it clears bits in case auto-negotiation has not completed. +Also clear 10GBT link-partner advertisement bits in case auto-negotiation +is disabled or has not completed. + +Suggested-by: Russell King (Oracle) +Signed-off-by: Daniel Golle +Link: https://patch.msgid.link/b15929a41621d215c6b2b57393368086589569ec.1728565530.git.daniel@makrotopia.org +Signed-off-by: Paolo Abeni +--- + drivers/net/phy/realtek.c | 22 +++++++++++++++------- + 1 file changed, 15 insertions(+), 7 deletions(-) + +--- a/drivers/net/phy/realtek.c ++++ b/drivers/net/phy/realtek.c +@@ -949,17 +949,25 @@ static void rtl822xb_update_interface(st + + static int rtl822x_read_status(struct phy_device *phydev) + { +- if (phydev->autoneg == AUTONEG_ENABLE) { +- int lpadv = phy_read_paged(phydev, 0xa5d, 0x13); ++ int lpadv, ret; + +- if (lpadv < 0) +- return lpadv; ++ ret = rtlgen_read_status(phydev); ++ if (ret < 0) ++ return ret; + +- mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, +- lpadv); ++ if (phydev->autoneg == AUTONEG_DISABLE || ++ !phydev->autoneg_complete) { ++ mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, 0); ++ return 0; + } + +- return rtlgen_read_status(phydev); ++ lpadv = phy_read_paged(phydev, 0xa5d, 0x13); ++ if (lpadv < 0) ++ return lpadv; ++ ++ mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, lpadv); ++ ++ return 0; + } + + static int rtl822xb_read_status(struct phy_device *phydev) diff --git a/target/linux/generic/backport-6.12/781-03-v6.13-net-phy-realtek-clear-1000Base-T-link-partner-advert.patch b/target/linux/generic/backport-6.12/781-03-v6.13-net-phy-realtek-clear-1000Base-T-link-partner-advert.patch new file mode 100644 index 0000000000..60cd125a22 --- /dev/null +++ b/target/linux/generic/backport-6.12/781-03-v6.13-net-phy-realtek-clear-1000Base-T-link-partner-advert.patch @@ -0,0 +1,30 @@ +From 5cb409b3960e75467cbb0a8e1e5596b4490570e3 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 10 Oct 2024 14:07:39 +0100 +Subject: [PATCH] net: phy: realtek: clear 1000Base-T link partner + advertisement + +Clear 1000Base-T link partner advertisement bits in Clause-45 +read_status() function in case auto-negotiation is disabled or has not +been completed. + +Signed-off-by: Daniel Golle +Link: https://patch.msgid.link/9dc9b47b2d675708afef3ad366bfd78eb584d958.1728565530.git.daniel@makrotopia.org +Signed-off-by: Paolo Abeni +--- + drivers/net/phy/realtek.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/net/phy/realtek.c ++++ b/drivers/net/phy/realtek.c +@@ -1026,6 +1026,10 @@ static int rtl822x_c45_read_status(struc + if (ret < 0) + return ret; + ++ if (phydev->autoneg == AUTONEG_DISABLE || ++ !genphy_c45_aneg_done(phydev)) ++ mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, 0); ++ + /* Vendor register as C45 has no standardized support for 1000BaseT */ + if (phydev->autoneg == AUTONEG_ENABLE) { + val = phy_read_mmd(phydev, MDIO_MMD_VEND2, diff --git a/target/linux/generic/backport-6.12/781-04-v6.13-net-phy-realtek-merge-the-drivers-for-internal-NBase.patch b/target/linux/generic/backport-6.12/781-04-v6.13-net-phy-realtek-merge-the-drivers-for-internal-NBase.patch new file mode 100644 index 0000000000..771f60df91 --- /dev/null +++ b/target/linux/generic/backport-6.12/781-04-v6.13-net-phy-realtek-merge-the-drivers-for-internal-NBase.patch @@ -0,0 +1,136 @@ +From f87a17ed3b51fba4dfdd8f8b643b5423a85fc551 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Tue, 15 Oct 2024 07:47:14 +0200 +Subject: [PATCH] net: phy: realtek: merge the drivers for internal NBase-T + PHY's + +The Realtek RTL8125/RTL8126 NBase-T MAC/PHY chips have internal PHY's +which are register-compatible, at least for the registers we use here. +So let's use just one PHY driver to support all of them. +These internal PHY's exist also as external C45 PHY's, but on the +internal PHY's no access to MMD registers is possible. This can be +used to differentiate between the internal and external version. + +As a side effect the drivers for two now external-only drivers don't +require read_mmd/write_mmd hooks any longer. + +Signed-off-by: Heiner Kallweit +Link: https://patch.msgid.link/c57081a6-811f-4571-ab35-34f4ca6de9af@gmail.com +Signed-off-by: Paolo Abeni +--- + drivers/net/phy/realtek.c | 53 +++++++++++++++++++++++++++++++-------- + 1 file changed, 43 insertions(+), 10 deletions(-) + +--- a/drivers/net/phy/realtek.c ++++ b/drivers/net/phy/realtek.c +@@ -95,6 +95,7 @@ + + #define RTL_GENERIC_PHYID 0x001cc800 + #define RTL_8211FVD_PHYID 0x001cc878 ++#define RTL_8221B 0x001cc840 + #define RTL_8221B_VB_CG 0x001cc849 + #define RTL_8221B_VN_CG 0x001cc84a + #define RTL_8251B 0x001cc862 +@@ -1077,6 +1078,23 @@ static bool rtlgen_supports_2_5gbps(stru + return val >= 0 && val & MDIO_PMA_SPEED_2_5G; + } + ++/* On internal PHY's MMD reads over C22 always return 0. ++ * Check a MMD register which is known to be non-zero. ++ */ ++static bool rtlgen_supports_mmd(struct phy_device *phydev) ++{ ++ int val; ++ ++ phy_lock_mdio_bus(phydev); ++ __phy_write(phydev, MII_MMD_CTRL, MDIO_MMD_PCS); ++ __phy_write(phydev, MII_MMD_DATA, MDIO_PCS_EEE_ABLE); ++ __phy_write(phydev, MII_MMD_CTRL, MDIO_MMD_PCS | MII_MMD_CTRL_NOINCR); ++ val = __phy_read(phydev, MII_MMD_DATA); ++ phy_unlock_mdio_bus(phydev); ++ ++ return val > 0; ++} ++ + static int rtlgen_match_phy_device(struct phy_device *phydev) + { + return phydev->phy_id == RTL_GENERIC_PHYID && +@@ -1086,7 +1104,8 @@ static int rtlgen_match_phy_device(struc + static int rtl8226_match_phy_device(struct phy_device *phydev) + { + return phydev->phy_id == RTL_GENERIC_PHYID && +- rtlgen_supports_2_5gbps(phydev); ++ rtlgen_supports_2_5gbps(phydev) && ++ rtlgen_supports_mmd(phydev); + } + + static int rtlgen_is_c45_match(struct phy_device *phydev, unsigned int id, +@@ -1098,6 +1117,11 @@ static int rtlgen_is_c45_match(struct ph + return !is_c45 && (id == phydev->phy_id); + } + ++static int rtl8221b_match_phy_device(struct phy_device *phydev) ++{ ++ return phydev->phy_id == RTL_8221B && rtlgen_supports_mmd(phydev); ++} ++ + static int rtl8221b_vb_cg_c22_match_phy_device(struct phy_device *phydev) + { + return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, false); +@@ -1118,9 +1142,21 @@ static int rtl8221b_vn_cg_c45_match_phy_ + return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, true); + } + +-static int rtl8251b_c22_match_phy_device(struct phy_device *phydev) ++static int rtl_internal_nbaset_match_phy_device(struct phy_device *phydev) + { +- return rtlgen_is_c45_match(phydev, RTL_8251B, false); ++ if (phydev->is_c45) ++ return false; ++ ++ switch (phydev->phy_id) { ++ case RTL_GENERIC_PHYID: ++ case RTL_8221B: ++ case RTL_8251B: ++ break; ++ default: ++ return false; ++ } ++ ++ return rtlgen_supports_2_5gbps(phydev) && !rtlgen_supports_mmd(phydev); + } + + static int rtl8251b_c45_match_phy_device(struct phy_device *phydev) +@@ -1382,10 +1418,8 @@ static struct phy_driver realtek_drvs[] + .resume = rtlgen_resume, + .read_page = rtl821x_read_page, + .write_page = rtl821x_write_page, +- .read_mmd = rtl822x_read_mmd, +- .write_mmd = rtl822x_write_mmd, + }, { +- PHY_ID_MATCH_EXACT(0x001cc840), ++ .match_phy_device = rtl8221b_match_phy_device, + .name = "RTL8226B_RTL8221B 2.5Gbps PHY", + .get_features = rtl822x_get_features, + .config_aneg = rtl822x_config_aneg, +@@ -1396,8 +1430,6 @@ static struct phy_driver realtek_drvs[] + .resume = rtlgen_resume, + .read_page = rtl821x_read_page, + .write_page = rtl821x_write_page, +- .read_mmd = rtl822x_read_mmd, +- .write_mmd = rtl822x_write_mmd, + }, { + PHY_ID_MATCH_EXACT(0x001cc838), + .name = "RTL8226-CG 2.5Gbps PHY", +@@ -1475,8 +1507,9 @@ static struct phy_driver realtek_drvs[] + .read_page = rtl821x_read_page, + .write_page = rtl821x_write_page, + }, { +- .match_phy_device = rtl8251b_c22_match_phy_device, +- .name = "RTL8126A-internal 5Gbps PHY", ++ .match_phy_device = rtl_internal_nbaset_match_phy_device, ++ .name = "Realtek Internal NBASE-T PHY", ++ .flags = PHY_IS_INTERNAL, + .get_features = rtl822x_get_features, + .config_aneg = rtl822x_config_aneg, + .read_status = rtl822x_read_status, diff --git a/target/linux/generic/backport-6.12/781-05-v6.13-net-phy-realtek-add-RTL8125D-internal-PHY.patch b/target/linux/generic/backport-6.12/781-05-v6.13-net-phy-realtek-add-RTL8125D-internal-PHY.patch new file mode 100644 index 0000000000..4b9b9e8d48 --- /dev/null +++ b/target/linux/generic/backport-6.12/781-05-v6.13-net-phy-realtek-add-RTL8125D-internal-PHY.patch @@ -0,0 +1,29 @@ +From 8989bad541133c43550bff2b80edbe37b8fb9659 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Thu, 17 Oct 2024 18:01:13 +0200 +Subject: [PATCH] net: phy: realtek: add RTL8125D-internal PHY + +The first boards show up with Realtek's RTL8125D. This MAC/PHY chip +comes with an integrated 2.5Gbps PHY with ID 0x001cc841. It's not +clear yet whether there's an external version of this PHY and how +Realtek calls it, therefore use the numeric id for now. + +Link: https://lore.kernel.org/netdev/2ada65e1-5dfa-456c-9334-2bc51272e9da@gmail.com/T/ +Signed-off-by: Heiner Kallweit +Message-ID: <7d2924de-053b-44d2-a479-870dc3878170@gmail.com> +Reviewed-by: Andrew Lunn +Signed-off-by: Andrew Lunn +--- + drivers/net/phy/realtek.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/net/phy/realtek.c ++++ b/drivers/net/phy/realtek.c +@@ -1151,6 +1151,7 @@ static int rtl_internal_nbaset_match_phy + case RTL_GENERIC_PHYID: + case RTL_8221B: + case RTL_8251B: ++ case 0x001cc841: + break; + default: + return false; diff --git a/target/linux/generic/backport-6.12/781-06-v6.14-net-phy-realtek-add-support-for-reading-MDIO_MMD_VEN.patch b/target/linux/generic/backport-6.12/781-06-v6.14-net-phy-realtek-add-support-for-reading-MDIO_MMD_VEN.patch new file mode 100644 index 0000000000..2add672f44 --- /dev/null +++ b/target/linux/generic/backport-6.12/781-06-v6.14-net-phy-realtek-add-support-for-reading-MDIO_MMD_VEN.patch @@ -0,0 +1,47 @@ +From 3d483a10327f38595f714f9f9e9dde43a622cb0f Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Sat, 11 Jan 2025 21:49:31 +0100 +Subject: [PATCH] net: phy: realtek: add support for reading MDIO_MMD_VEND2 + regs on RTL8125/RTL8126 + +RTL8125/RTL8126 don't support MMD access to the internal PHY, but +provide a mechanism to access at least all MDIO_MMD_VEND2 registers. +By exposing this mechanism standard MMD access functions can be used +to access the MDIO_MMD_VEND2 registers. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/e821b302-5fe6-49ab-aabd-05da500581c0@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/realtek.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +--- a/drivers/net/phy/realtek.c ++++ b/drivers/net/phy/realtek.c +@@ -736,7 +736,11 @@ static int rtlgen_read_mmd(struct phy_de + { + int ret; + +- if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) { ++ if (devnum == MDIO_MMD_VEND2) { ++ rtl821x_write_page(phydev, regnum >> 4); ++ ret = __phy_read(phydev, 0x10 + ((regnum & 0xf) >> 1)); ++ rtl821x_write_page(phydev, 0); ++ } else if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) { + rtl821x_write_page(phydev, 0xa5c); + ret = __phy_read(phydev, 0x12); + rtl821x_write_page(phydev, 0); +@@ -760,7 +764,11 @@ static int rtlgen_write_mmd(struct phy_d + { + int ret; + +- if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) { ++ if (devnum == MDIO_MMD_VEND2) { ++ rtl821x_write_page(phydev, regnum >> 4); ++ ret = __phy_write(phydev, 0x10 + ((regnum & 0xf) >> 1), val); ++ rtl821x_write_page(phydev, 0); ++ } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) { + rtl821x_write_page(phydev, 0xa5d); + ret = __phy_write(phydev, 0x10, val); + rtl821x_write_page(phydev, 0); diff --git a/target/linux/generic/backport-6.12/781-07-v6.14-net-phy-realtek-clear-1000Base-T-lpa-if-link-is-down.patch b/target/linux/generic/backport-6.12/781-07-v6.14-net-phy-realtek-clear-1000Base-T-lpa-if-link-is-down.patch new file mode 100644 index 0000000000..002b99e4d5 --- /dev/null +++ b/target/linux/generic/backport-6.12/781-07-v6.14-net-phy-realtek-clear-1000Base-T-lpa-if-link-is-down.patch @@ -0,0 +1,52 @@ +From 34d5a86ff7bbe225fba3ad91f9b4dc85fb408e18 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Wed, 15 Jan 2025 14:43:35 +0000 +Subject: [PATCH] net: phy: realtek: clear 1000Base-T lpa if link is down + +Only read 1000Base-T link partner advertisement if autonegotiation has +completed and otherwise 1000Base-T link partner advertisement bits. + +This fixes bogus 1000Base-T link partner advertisement after link goes +down (eg. by disconnecting the wire). +Fixes: 5cb409b3960e ("net: phy: realtek: clear 1000Base-T link partner advertisement") +Signed-off-by: Daniel Golle +Reviewed-by: Michal Swiatkowski +Signed-off-by: David S. Miller +--- + drivers/net/phy/realtek.c | 19 ++++++++----------- + 1 file changed, 8 insertions(+), 11 deletions(-) + +--- a/drivers/net/phy/realtek.c ++++ b/drivers/net/phy/realtek.c +@@ -1031,23 +1031,20 @@ static int rtl822x_c45_read_status(struc + { + int ret, val; + +- ret = genphy_c45_read_status(phydev); +- if (ret < 0) +- return ret; +- +- if (phydev->autoneg == AUTONEG_DISABLE || +- !genphy_c45_aneg_done(phydev)) +- mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, 0); +- + /* Vendor register as C45 has no standardized support for 1000BaseT */ +- if (phydev->autoneg == AUTONEG_ENABLE) { ++ if (phydev->autoneg == AUTONEG_ENABLE && genphy_c45_aneg_done(phydev)) { + val = phy_read_mmd(phydev, MDIO_MMD_VEND2, + RTL822X_VND2_GANLPAR); + if (val < 0) + return val; +- +- mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, val); ++ } else { ++ val = 0; + } ++ mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, val); ++ ++ ret = genphy_c45_read_status(phydev); ++ if (ret < 0) ++ return ret; + + if (!phydev->link) + return 0; diff --git a/target/linux/generic/backport-6.12/781-08-v6.14-net-phy-realtek-clear-master_slave_state-if-link-is-.patch b/target/linux/generic/backport-6.12/781-08-v6.14-net-phy-realtek-clear-master_slave_state-if-link-is-.patch new file mode 100644 index 0000000000..f8cfc4d131 --- /dev/null +++ b/target/linux/generic/backport-6.12/781-08-v6.14-net-phy-realtek-clear-master_slave_state-if-link-is-.patch @@ -0,0 +1,35 @@ +From ea8318cb33e593bbfc59d637eae45a69732c5387 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Wed, 15 Jan 2025 14:43:43 +0000 +Subject: [PATCH] net: phy: realtek: clear master_slave_state if link is down + +rtlgen_decode_physr() which sets master_slave_state isn't called in case +the link is down and other than rtlgen_read_status(), +rtl822x_c45_read_status() doesn't implicitely clear master_slave_state. + +Avoid stale master_slave_state by always setting it to +MASTER_SLAVE_STATE_UNKNOWN in rtl822x_c45_read_status() in case the link +is down. + +Fixes: 081c9c0265c9 ("net: phy: realtek: read duplex and gbit master from PHYSR register") +Signed-off-by: Daniel Golle +Reviewed-by: Michal Swiatkowski +Signed-off-by: David S. Miller +--- + drivers/net/phy/realtek.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/net/phy/realtek.c ++++ b/drivers/net/phy/realtek.c +@@ -1046,8 +1046,10 @@ static int rtl822x_c45_read_status(struc + if (ret < 0) + return ret; + +- if (!phydev->link) ++ if (!phydev->link) { ++ phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN; + return 0; ++ } + + /* Read actual speed from vendor register. */ + val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL_VND2_PHYSR); diff --git a/target/linux/generic/backport-6.12/781-09-v6.14-net-phy-realtek-always-clear-NBase-T-lpa.patch b/target/linux/generic/backport-6.12/781-09-v6.14-net-phy-realtek-always-clear-NBase-T-lpa.patch new file mode 100644 index 0000000000..e628bed6b4 --- /dev/null +++ b/target/linux/generic/backport-6.12/781-09-v6.14-net-phy-realtek-always-clear-NBase-T-lpa.patch @@ -0,0 +1,42 @@ +From d3eb58549842c60ed46f37da7f4da969e3d6ecd3 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Wed, 15 Jan 2025 14:45:00 +0000 +Subject: [PATCH] net: phy: realtek: always clear NBase-T lpa + +Clear NBase-T link partner advertisement before calling +rtlgen_read_status() to avoid phy_resolve_aneg_linkmode() wrongly +setting speed and duplex. + +This fixes bogus 2.5G/5G/10G link partner advertisement and thus +speed and duplex being set by phy_resolve_aneg_linkmode() due to stale +NBase-T lpa. + +Fixes: 68d5cd09e891 ("net: phy: realtek: change order of calls in C22 read_status()") +Signed-off-by: Daniel Golle +Reviewed-by: Michal Swiatkowski +Signed-off-by: David S. Miller +--- + drivers/net/phy/realtek.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/net/phy/realtek.c ++++ b/drivers/net/phy/realtek.c +@@ -960,15 +960,15 @@ static int rtl822x_read_status(struct ph + { + int lpadv, ret; + ++ mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, 0); ++ + ret = rtlgen_read_status(phydev); + if (ret < 0) + return ret; + + if (phydev->autoneg == AUTONEG_DISABLE || +- !phydev->autoneg_complete) { +- mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, 0); ++ !phydev->autoneg_complete) + return 0; +- } + + lpadv = phy_read_paged(phydev, 0xa5d, 0x13); + if (lpadv < 0) diff --git a/target/linux/generic/backport-6.12/781-10-v6.14-net-phy-move-realtek-PHY-driver-to-its-own-subdirect.patch b/target/linux/generic/backport-6.12/781-10-v6.14-net-phy-move-realtek-PHY-driver-to-its-own-subdirect.patch new file mode 100644 index 0000000000..5f0b61e0ce --- /dev/null +++ b/target/linux/generic/backport-6.12/781-10-v6.14-net-phy-move-realtek-PHY-driver-to-its-own-subdirect.patch @@ -0,0 +1,3247 @@ +From 1416a9b2ba710d31954131c06d46f298e340aa2c Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Sat, 11 Jan 2025 21:50:19 +0100 +Subject: [PATCH] net: phy: move realtek PHY driver to its own subdirectory + +In preparation of adding a source file with hwmon support, move the +Realtek PHY driver to its own subdirectory and rename realtek.c to +realtek_main.c. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/c566551b-c915-4e34-9b33-129a6ddd6e4c@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/Kconfig | 5 +---- + drivers/net/phy/Makefile | 2 +- + drivers/net/phy/realtek/Kconfig | 5 +++++ + drivers/net/phy/realtek/Makefile | 3 +++ + drivers/net/phy/{realtek.c => realtek/realtek_main.c} | 0 + 5 files changed, 10 insertions(+), 5 deletions(-) + create mode 100644 drivers/net/phy/realtek/Kconfig + create mode 100644 drivers/net/phy/realtek/Makefile + rename drivers/net/phy/{realtek.c => realtek/realtek_main.c} (100%) + +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -358,10 +358,7 @@ config QSEMI_PHY + help + Currently supports the qs6612 + +-config REALTEK_PHY +- tristate "Realtek PHYs" +- help +- Supports the Realtek 821x PHY. ++source "drivers/net/phy/realtek/Kconfig" + + config RENESAS_PHY + tristate "Renesas PHYs" +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -95,7 +95,7 @@ obj-$(CONFIG_NXP_CBTX_PHY) += nxp-cbtx.o + obj-$(CONFIG_NXP_TJA11XX_PHY) += nxp-tja11xx.o + obj-y += qcom/ + obj-$(CONFIG_QSEMI_PHY) += qsemi.o +-obj-$(CONFIG_REALTEK_PHY) += realtek.o ++obj-$(CONFIG_REALTEK_PHY) += realtek/ + obj-$(CONFIG_RENESAS_PHY) += uPD60620.o + obj-$(CONFIG_ROCKCHIP_PHY) += rockchip.o + obj-$(CONFIG_SMSC_PHY) += smsc.o +--- /dev/null ++++ b/drivers/net/phy/realtek/Kconfig +@@ -0,0 +1,5 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++config REALTEK_PHY ++ tristate "Realtek PHYs" ++ help ++ Currently supports RTL821x/RTL822x and fast ethernet PHYs +--- /dev/null ++++ b/drivers/net/phy/realtek/Makefile +@@ -0,0 +1,3 @@ ++# SPDX-License-Identifier: GPL-2.0 ++realtek-y += realtek_main.o ++obj-$(CONFIG_REALTEK_PHY) += realtek.o +--- a/drivers/net/phy/realtek.c ++++ /dev/null +@@ -1,1589 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0+ +-/* drivers/net/phy/realtek.c +- * +- * Driver for Realtek PHYs +- * +- * Author: Johnson Leung +- * +- * Copyright (c) 2004 Freescale Semiconductor, Inc. +- */ +-#include +-#include +-#include +-#include +-#include +-#include +- +-#define RTL821x_PHYSR 0x11 +-#define RTL821x_PHYSR_DUPLEX BIT(13) +-#define RTL821x_PHYSR_SPEED GENMASK(15, 14) +- +-#define RTL821x_INER 0x12 +-#define RTL8211B_INER_INIT 0x6400 +-#define RTL8211E_INER_LINK_STATUS BIT(10) +-#define RTL8211F_INER_LINK_STATUS BIT(4) +- +-#define RTL821x_INSR 0x13 +- +-#define RTL821x_EXT_PAGE_SELECT 0x1e +-#define RTL821x_PAGE_SELECT 0x1f +- +-#define RTL8211F_PHYCR1 0x18 +-#define RTL8211F_PHYCR2 0x19 +-#define RTL8211F_INSR 0x1d +- +-#define RTL8211F_LEDCR 0x10 +-#define RTL8211F_LEDCR_MODE BIT(15) +-#define RTL8211F_LEDCR_ACT_TXRX BIT(4) +-#define RTL8211F_LEDCR_LINK_1000 BIT(3) +-#define RTL8211F_LEDCR_LINK_100 BIT(1) +-#define RTL8211F_LEDCR_LINK_10 BIT(0) +-#define RTL8211F_LEDCR_MASK GENMASK(4, 0) +-#define RTL8211F_LEDCR_SHIFT 5 +- +-#define RTL8211F_TX_DELAY BIT(8) +-#define RTL8211F_RX_DELAY BIT(3) +- +-#define RTL8211F_ALDPS_PLL_OFF BIT(1) +-#define RTL8211F_ALDPS_ENABLE BIT(2) +-#define RTL8211F_ALDPS_XTAL_OFF BIT(12) +- +-#define RTL8211E_CTRL_DELAY BIT(13) +-#define RTL8211E_TX_DELAY BIT(12) +-#define RTL8211E_RX_DELAY BIT(11) +- +-#define RTL8211F_CLKOUT_EN BIT(0) +- +-#define RTL8201F_ISR 0x1e +-#define RTL8201F_ISR_ANERR BIT(15) +-#define RTL8201F_ISR_DUPLEX BIT(13) +-#define RTL8201F_ISR_LINK BIT(11) +-#define RTL8201F_ISR_MASK (RTL8201F_ISR_ANERR | \ +- RTL8201F_ISR_DUPLEX | \ +- RTL8201F_ISR_LINK) +-#define RTL8201F_IER 0x13 +- +-#define RTL822X_VND1_SERDES_OPTION 0x697a +-#define RTL822X_VND1_SERDES_OPTION_MODE_MASK GENMASK(5, 0) +-#define RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII 0 +-#define RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX 2 +- +-#define RTL822X_VND1_SERDES_CTRL3 0x7580 +-#define RTL822X_VND1_SERDES_CTRL3_MODE_MASK GENMASK(5, 0) +-#define RTL822X_VND1_SERDES_CTRL3_MODE_SGMII 0x02 +-#define RTL822X_VND1_SERDES_CTRL3_MODE_2500BASEX 0x16 +- +-/* RTL822X_VND2_XXXXX registers are only accessible when phydev->is_c45 +- * is set, they cannot be accessed by C45-over-C22. +- */ +-#define RTL822X_VND2_GBCR 0xa412 +- +-#define RTL822X_VND2_GANLPAR 0xa414 +- +-#define RTL8366RB_POWER_SAVE 0x15 +-#define RTL8366RB_POWER_SAVE_ON BIT(12) +- +-#define RTL9000A_GINMR 0x14 +-#define RTL9000A_GINMR_LINK_STATUS BIT(4) +- +-#define RTL_VND2_PHYSR 0xa434 +-#define RTL_VND2_PHYSR_DUPLEX BIT(3) +-#define RTL_VND2_PHYSR_SPEEDL GENMASK(5, 4) +-#define RTL_VND2_PHYSR_SPEEDH GENMASK(10, 9) +-#define RTL_VND2_PHYSR_MASTER BIT(11) +-#define RTL_VND2_PHYSR_SPEED_MASK (RTL_VND2_PHYSR_SPEEDL | RTL_VND2_PHYSR_SPEEDH) +- +-#define RTL_GENERIC_PHYID 0x001cc800 +-#define RTL_8211FVD_PHYID 0x001cc878 +-#define RTL_8221B 0x001cc840 +-#define RTL_8221B_VB_CG 0x001cc849 +-#define RTL_8221B_VN_CG 0x001cc84a +-#define RTL_8251B 0x001cc862 +- +-#define RTL8211F_LED_COUNT 3 +- +-MODULE_DESCRIPTION("Realtek PHY driver"); +-MODULE_AUTHOR("Johnson Leung"); +-MODULE_LICENSE("GPL"); +- +-struct rtl821x_priv { +- u16 phycr1; +- u16 phycr2; +- bool has_phycr2; +- struct clk *clk; +-}; +- +-static int rtl821x_read_page(struct phy_device *phydev) +-{ +- return __phy_read(phydev, RTL821x_PAGE_SELECT); +-} +- +-static int rtl821x_write_page(struct phy_device *phydev, int page) +-{ +- return __phy_write(phydev, RTL821x_PAGE_SELECT, page); +-} +- +-static int rtl821x_probe(struct phy_device *phydev) +-{ +- struct device *dev = &phydev->mdio.dev; +- struct rtl821x_priv *priv; +- u32 phy_id = phydev->drv->phy_id; +- int ret; +- +- priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); +- if (!priv) +- return -ENOMEM; +- +- priv->clk = devm_clk_get_optional_enabled(dev, NULL); +- if (IS_ERR(priv->clk)) +- return dev_err_probe(dev, PTR_ERR(priv->clk), +- "failed to get phy clock\n"); +- +- ret = phy_read_paged(phydev, 0xa43, RTL8211F_PHYCR1); +- if (ret < 0) +- return ret; +- +- priv->phycr1 = ret & (RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF); +- if (of_property_read_bool(dev->of_node, "realtek,aldps-enable")) +- priv->phycr1 |= RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF; +- +- priv->has_phycr2 = !(phy_id == RTL_8211FVD_PHYID); +- if (priv->has_phycr2) { +- ret = phy_read_paged(phydev, 0xa43, RTL8211F_PHYCR2); +- if (ret < 0) +- return ret; +- +- priv->phycr2 = ret & RTL8211F_CLKOUT_EN; +- if (of_property_read_bool(dev->of_node, "realtek,clkout-disable")) +- priv->phycr2 &= ~RTL8211F_CLKOUT_EN; +- } +- +- phydev->priv = priv; +- +- return 0; +-} +- +-static int rtl8201_ack_interrupt(struct phy_device *phydev) +-{ +- int err; +- +- err = phy_read(phydev, RTL8201F_ISR); +- +- return (err < 0) ? err : 0; +-} +- +-static int rtl821x_ack_interrupt(struct phy_device *phydev) +-{ +- int err; +- +- err = phy_read(phydev, RTL821x_INSR); +- +- return (err < 0) ? err : 0; +-} +- +-static int rtl8211f_ack_interrupt(struct phy_device *phydev) +-{ +- int err; +- +- err = phy_read_paged(phydev, 0xa43, RTL8211F_INSR); +- +- return (err < 0) ? err : 0; +-} +- +-static int rtl8201_config_intr(struct phy_device *phydev) +-{ +- u16 val; +- int err; +- +- if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { +- err = rtl8201_ack_interrupt(phydev); +- if (err) +- return err; +- +- val = BIT(13) | BIT(12) | BIT(11); +- err = phy_write_paged(phydev, 0x7, RTL8201F_IER, val); +- } else { +- val = 0; +- err = phy_write_paged(phydev, 0x7, RTL8201F_IER, val); +- if (err) +- return err; +- +- err = rtl8201_ack_interrupt(phydev); +- } +- +- return err; +-} +- +-static int rtl8211b_config_intr(struct phy_device *phydev) +-{ +- int err; +- +- if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { +- err = rtl821x_ack_interrupt(phydev); +- if (err) +- return err; +- +- err = phy_write(phydev, RTL821x_INER, +- RTL8211B_INER_INIT); +- } else { +- err = phy_write(phydev, RTL821x_INER, 0); +- if (err) +- return err; +- +- err = rtl821x_ack_interrupt(phydev); +- } +- +- return err; +-} +- +-static int rtl8211e_config_intr(struct phy_device *phydev) +-{ +- int err; +- +- if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { +- err = rtl821x_ack_interrupt(phydev); +- if (err) +- return err; +- +- err = phy_write(phydev, RTL821x_INER, +- RTL8211E_INER_LINK_STATUS); +- } else { +- err = phy_write(phydev, RTL821x_INER, 0); +- if (err) +- return err; +- +- err = rtl821x_ack_interrupt(phydev); +- } +- +- return err; +-} +- +-static int rtl8211f_config_intr(struct phy_device *phydev) +-{ +- u16 val; +- int err; +- +- if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { +- err = rtl8211f_ack_interrupt(phydev); +- if (err) +- return err; +- +- val = RTL8211F_INER_LINK_STATUS; +- err = phy_write_paged(phydev, 0xa42, RTL821x_INER, val); +- } else { +- val = 0; +- err = phy_write_paged(phydev, 0xa42, RTL821x_INER, val); +- if (err) +- return err; +- +- err = rtl8211f_ack_interrupt(phydev); +- } +- +- return err; +-} +- +-static irqreturn_t rtl8201_handle_interrupt(struct phy_device *phydev) +-{ +- int irq_status; +- +- irq_status = phy_read(phydev, RTL8201F_ISR); +- if (irq_status < 0) { +- phy_error(phydev); +- return IRQ_NONE; +- } +- +- if (!(irq_status & RTL8201F_ISR_MASK)) +- return IRQ_NONE; +- +- phy_trigger_machine(phydev); +- +- return IRQ_HANDLED; +-} +- +-static irqreturn_t rtl821x_handle_interrupt(struct phy_device *phydev) +-{ +- int irq_status, irq_enabled; +- +- irq_status = phy_read(phydev, RTL821x_INSR); +- if (irq_status < 0) { +- phy_error(phydev); +- return IRQ_NONE; +- } +- +- irq_enabled = phy_read(phydev, RTL821x_INER); +- if (irq_enabled < 0) { +- phy_error(phydev); +- return IRQ_NONE; +- } +- +- if (!(irq_status & irq_enabled)) +- return IRQ_NONE; +- +- phy_trigger_machine(phydev); +- +- return IRQ_HANDLED; +-} +- +-static irqreturn_t rtl8211f_handle_interrupt(struct phy_device *phydev) +-{ +- int irq_status; +- +- irq_status = phy_read_paged(phydev, 0xa43, RTL8211F_INSR); +- if (irq_status < 0) { +- phy_error(phydev); +- return IRQ_NONE; +- } +- +- if (!(irq_status & RTL8211F_INER_LINK_STATUS)) +- return IRQ_NONE; +- +- phy_trigger_machine(phydev); +- +- return IRQ_HANDLED; +-} +- +-static int rtl8211_config_aneg(struct phy_device *phydev) +-{ +- int ret; +- +- ret = genphy_config_aneg(phydev); +- if (ret < 0) +- return ret; +- +- /* Quirk was copied from vendor driver. Unfortunately it includes no +- * description of the magic numbers. +- */ +- if (phydev->speed == SPEED_100 && phydev->autoneg == AUTONEG_DISABLE) { +- phy_write(phydev, 0x17, 0x2138); +- phy_write(phydev, 0x0e, 0x0260); +- } else { +- phy_write(phydev, 0x17, 0x2108); +- phy_write(phydev, 0x0e, 0x0000); +- } +- +- return 0; +-} +- +-static int rtl8211c_config_init(struct phy_device *phydev) +-{ +- /* RTL8211C has an issue when operating in Gigabit slave mode */ +- return phy_set_bits(phydev, MII_CTRL1000, +- CTL1000_ENABLE_MASTER | CTL1000_AS_MASTER); +-} +- +-static int rtl8211f_config_init(struct phy_device *phydev) +-{ +- struct rtl821x_priv *priv = phydev->priv; +- struct device *dev = &phydev->mdio.dev; +- u16 val_txdly, val_rxdly; +- int ret; +- +- ret = phy_modify_paged_changed(phydev, 0xa43, RTL8211F_PHYCR1, +- RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF, +- priv->phycr1); +- if (ret < 0) { +- dev_err(dev, "aldps mode configuration failed: %pe\n", +- ERR_PTR(ret)); +- return ret; +- } +- +- switch (phydev->interface) { +- case PHY_INTERFACE_MODE_RGMII: +- val_txdly = 0; +- val_rxdly = 0; +- break; +- +- case PHY_INTERFACE_MODE_RGMII_RXID: +- val_txdly = 0; +- val_rxdly = RTL8211F_RX_DELAY; +- break; +- +- case PHY_INTERFACE_MODE_RGMII_TXID: +- val_txdly = RTL8211F_TX_DELAY; +- val_rxdly = 0; +- break; +- +- case PHY_INTERFACE_MODE_RGMII_ID: +- val_txdly = RTL8211F_TX_DELAY; +- val_rxdly = RTL8211F_RX_DELAY; +- break; +- +- default: /* the rest of the modes imply leaving delay as is. */ +- return 0; +- } +- +- ret = phy_modify_paged_changed(phydev, 0xd08, 0x11, RTL8211F_TX_DELAY, +- val_txdly); +- if (ret < 0) { +- dev_err(dev, "Failed to update the TX delay register\n"); +- return ret; +- } else if (ret) { +- dev_dbg(dev, +- "%s 2ns TX delay (and changing the value from pin-strapping RXD1 or the bootloader)\n", +- val_txdly ? "Enabling" : "Disabling"); +- } else { +- dev_dbg(dev, +- "2ns TX delay was already %s (by pin-strapping RXD1 or bootloader configuration)\n", +- val_txdly ? "enabled" : "disabled"); +- } +- +- ret = phy_modify_paged_changed(phydev, 0xd08, 0x15, RTL8211F_RX_DELAY, +- val_rxdly); +- if (ret < 0) { +- dev_err(dev, "Failed to update the RX delay register\n"); +- return ret; +- } else if (ret) { +- dev_dbg(dev, +- "%s 2ns RX delay (and changing the value from pin-strapping RXD0 or the bootloader)\n", +- val_rxdly ? "Enabling" : "Disabling"); +- } else { +- dev_dbg(dev, +- "2ns RX delay was already %s (by pin-strapping RXD0 or bootloader configuration)\n", +- val_rxdly ? "enabled" : "disabled"); +- } +- +- if (priv->has_phycr2) { +- ret = phy_modify_paged(phydev, 0xa43, RTL8211F_PHYCR2, +- RTL8211F_CLKOUT_EN, priv->phycr2); +- if (ret < 0) { +- dev_err(dev, "clkout configuration failed: %pe\n", +- ERR_PTR(ret)); +- return ret; +- } +- +- return genphy_soft_reset(phydev); +- } +- +- return 0; +-} +- +-static int rtl821x_suspend(struct phy_device *phydev) +-{ +- struct rtl821x_priv *priv = phydev->priv; +- int ret = 0; +- +- if (!phydev->wol_enabled) { +- ret = genphy_suspend(phydev); +- +- if (ret) +- return ret; +- +- clk_disable_unprepare(priv->clk); +- } +- +- return ret; +-} +- +-static int rtl821x_resume(struct phy_device *phydev) +-{ +- struct rtl821x_priv *priv = phydev->priv; +- int ret; +- +- if (!phydev->wol_enabled) +- clk_prepare_enable(priv->clk); +- +- ret = genphy_resume(phydev); +- if (ret < 0) +- return ret; +- +- msleep(20); +- +- return 0; +-} +- +-static int rtl8211f_led_hw_is_supported(struct phy_device *phydev, u8 index, +- unsigned long rules) +-{ +- const unsigned long mask = BIT(TRIGGER_NETDEV_LINK_10) | +- BIT(TRIGGER_NETDEV_LINK_100) | +- BIT(TRIGGER_NETDEV_LINK_1000) | +- BIT(TRIGGER_NETDEV_RX) | +- BIT(TRIGGER_NETDEV_TX); +- +- /* The RTL8211F PHY supports these LED settings on up to three LEDs: +- * - Link: Configurable subset of 10/100/1000 link rates +- * - Active: Blink on activity, RX or TX is not differentiated +- * The Active option has two modes, A and B: +- * - A: Link and Active indication at configurable, but matching, +- * subset of 10/100/1000 link rates +- * - B: Link indication at configurable subset of 10/100/1000 link +- * rates and Active indication always at all three 10+100+1000 +- * link rates. +- * This code currently uses mode B only. +- */ +- +- if (index >= RTL8211F_LED_COUNT) +- return -EINVAL; +- +- /* Filter out any other unsupported triggers. */ +- if (rules & ~mask) +- return -EOPNOTSUPP; +- +- /* RX and TX are not differentiated, either both are set or not set. */ +- if (!(rules & BIT(TRIGGER_NETDEV_RX)) ^ !(rules & BIT(TRIGGER_NETDEV_TX))) +- return -EOPNOTSUPP; +- +- return 0; +-} +- +-static int rtl8211f_led_hw_control_get(struct phy_device *phydev, u8 index, +- unsigned long *rules) +-{ +- int val; +- +- if (index >= RTL8211F_LED_COUNT) +- return -EINVAL; +- +- val = phy_read_paged(phydev, 0xd04, RTL8211F_LEDCR); +- if (val < 0) +- return val; +- +- val >>= RTL8211F_LEDCR_SHIFT * index; +- val &= RTL8211F_LEDCR_MASK; +- +- if (val & RTL8211F_LEDCR_LINK_10) +- set_bit(TRIGGER_NETDEV_LINK_10, rules); +- +- if (val & RTL8211F_LEDCR_LINK_100) +- set_bit(TRIGGER_NETDEV_LINK_100, rules); +- +- if (val & RTL8211F_LEDCR_LINK_1000) +- set_bit(TRIGGER_NETDEV_LINK_1000, rules); +- +- if (val & RTL8211F_LEDCR_ACT_TXRX) { +- set_bit(TRIGGER_NETDEV_RX, rules); +- set_bit(TRIGGER_NETDEV_TX, rules); +- } +- +- return 0; +-} +- +-static int rtl8211f_led_hw_control_set(struct phy_device *phydev, u8 index, +- unsigned long rules) +-{ +- const u16 mask = RTL8211F_LEDCR_MASK << (RTL8211F_LEDCR_SHIFT * index); +- u16 reg = 0; +- +- if (index >= RTL8211F_LED_COUNT) +- return -EINVAL; +- +- if (test_bit(TRIGGER_NETDEV_LINK_10, &rules)) +- reg |= RTL8211F_LEDCR_LINK_10; +- +- if (test_bit(TRIGGER_NETDEV_LINK_100, &rules)) +- reg |= RTL8211F_LEDCR_LINK_100; +- +- if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules)) +- reg |= RTL8211F_LEDCR_LINK_1000; +- +- if (test_bit(TRIGGER_NETDEV_RX, &rules) || +- test_bit(TRIGGER_NETDEV_TX, &rules)) { +- reg |= RTL8211F_LEDCR_ACT_TXRX; +- } +- +- reg <<= RTL8211F_LEDCR_SHIFT * index; +- reg |= RTL8211F_LEDCR_MODE; /* Mode B */ +- +- return phy_modify_paged(phydev, 0xd04, RTL8211F_LEDCR, mask, reg); +-} +- +-static int rtl8211e_config_init(struct phy_device *phydev) +-{ +- int ret = 0, oldpage; +- u16 val; +- +- /* enable TX/RX delay for rgmii-* modes, and disable them for rgmii. */ +- switch (phydev->interface) { +- case PHY_INTERFACE_MODE_RGMII: +- val = RTL8211E_CTRL_DELAY | 0; +- break; +- case PHY_INTERFACE_MODE_RGMII_ID: +- val = RTL8211E_CTRL_DELAY | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY; +- break; +- case PHY_INTERFACE_MODE_RGMII_RXID: +- val = RTL8211E_CTRL_DELAY | RTL8211E_RX_DELAY; +- break; +- case PHY_INTERFACE_MODE_RGMII_TXID: +- val = RTL8211E_CTRL_DELAY | RTL8211E_TX_DELAY; +- break; +- default: /* the rest of the modes imply leaving delays as is. */ +- return 0; +- } +- +- /* According to a sample driver there is a 0x1c config register on the +- * 0xa4 extension page (0x7) layout. It can be used to disable/enable +- * the RX/TX delays otherwise controlled by RXDLY/TXDLY pins. +- * The configuration register definition: +- * 14 = reserved +- * 13 = Force Tx RX Delay controlled by bit12 bit11, +- * 12 = RX Delay, 11 = TX Delay +- * 10:0 = Test && debug settings reserved by realtek +- */ +- oldpage = phy_select_page(phydev, 0x7); +- if (oldpage < 0) +- goto err_restore_page; +- +- ret = __phy_write(phydev, RTL821x_EXT_PAGE_SELECT, 0xa4); +- if (ret) +- goto err_restore_page; +- +- ret = __phy_modify(phydev, 0x1c, RTL8211E_CTRL_DELAY +- | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY, +- val); +- +-err_restore_page: +- return phy_restore_page(phydev, oldpage, ret); +-} +- +-static int rtl8211b_suspend(struct phy_device *phydev) +-{ +- phy_write(phydev, MII_MMD_DATA, BIT(9)); +- +- return genphy_suspend(phydev); +-} +- +-static int rtl8211b_resume(struct phy_device *phydev) +-{ +- phy_write(phydev, MII_MMD_DATA, 0); +- +- return genphy_resume(phydev); +-} +- +-static int rtl8366rb_config_init(struct phy_device *phydev) +-{ +- int ret; +- +- ret = phy_set_bits(phydev, RTL8366RB_POWER_SAVE, +- RTL8366RB_POWER_SAVE_ON); +- if (ret) { +- dev_err(&phydev->mdio.dev, +- "error enabling power management\n"); +- } +- +- return ret; +-} +- +-/* get actual speed to cover the downshift case */ +-static void rtlgen_decode_physr(struct phy_device *phydev, int val) +-{ +- /* bit 3 +- * 0: Half Duplex +- * 1: Full Duplex +- */ +- if (val & RTL_VND2_PHYSR_DUPLEX) +- phydev->duplex = DUPLEX_FULL; +- else +- phydev->duplex = DUPLEX_HALF; +- +- switch (val & RTL_VND2_PHYSR_SPEED_MASK) { +- case 0x0000: +- phydev->speed = SPEED_10; +- break; +- case 0x0010: +- phydev->speed = SPEED_100; +- break; +- case 0x0020: +- phydev->speed = SPEED_1000; +- break; +- case 0x0200: +- phydev->speed = SPEED_10000; +- break; +- case 0x0210: +- phydev->speed = SPEED_2500; +- break; +- case 0x0220: +- phydev->speed = SPEED_5000; +- break; +- default: +- break; +- } +- +- /* bit 11 +- * 0: Slave Mode +- * 1: Master Mode +- */ +- if (phydev->speed >= 1000) { +- if (val & RTL_VND2_PHYSR_MASTER) +- phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER; +- else +- phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE; +- } else { +- phydev->master_slave_state = MASTER_SLAVE_STATE_UNSUPPORTED; +- } +-} +- +-static int rtlgen_read_status(struct phy_device *phydev) +-{ +- int ret, val; +- +- ret = genphy_read_status(phydev); +- if (ret < 0) +- return ret; +- +- if (!phydev->link) +- return 0; +- +- val = phy_read_paged(phydev, 0xa43, 0x12); +- if (val < 0) +- return val; +- +- rtlgen_decode_physr(phydev, val); +- +- return 0; +-} +- +-static int rtlgen_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) +-{ +- int ret; +- +- if (devnum == MDIO_MMD_VEND2) { +- rtl821x_write_page(phydev, regnum >> 4); +- ret = __phy_read(phydev, 0x10 + ((regnum & 0xf) >> 1)); +- rtl821x_write_page(phydev, 0); +- } else if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) { +- rtl821x_write_page(phydev, 0xa5c); +- ret = __phy_read(phydev, 0x12); +- rtl821x_write_page(phydev, 0); +- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) { +- rtl821x_write_page(phydev, 0xa5d); +- ret = __phy_read(phydev, 0x10); +- rtl821x_write_page(phydev, 0); +- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE) { +- rtl821x_write_page(phydev, 0xa5d); +- ret = __phy_read(phydev, 0x11); +- rtl821x_write_page(phydev, 0); +- } else { +- ret = -EOPNOTSUPP; +- } +- +- return ret; +-} +- +-static int rtlgen_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, +- u16 val) +-{ +- int ret; +- +- if (devnum == MDIO_MMD_VEND2) { +- rtl821x_write_page(phydev, regnum >> 4); +- ret = __phy_write(phydev, 0x10 + ((regnum & 0xf) >> 1), val); +- rtl821x_write_page(phydev, 0); +- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) { +- rtl821x_write_page(phydev, 0xa5d); +- ret = __phy_write(phydev, 0x10, val); +- rtl821x_write_page(phydev, 0); +- } else { +- ret = -EOPNOTSUPP; +- } +- +- return ret; +-} +- +-static int rtl822x_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) +-{ +- int ret = rtlgen_read_mmd(phydev, devnum, regnum); +- +- if (ret != -EOPNOTSUPP) +- return ret; +- +- if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE2) { +- rtl821x_write_page(phydev, 0xa6e); +- ret = __phy_read(phydev, 0x16); +- rtl821x_write_page(phydev, 0); +- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) { +- rtl821x_write_page(phydev, 0xa6d); +- ret = __phy_read(phydev, 0x12); +- rtl821x_write_page(phydev, 0); +- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE2) { +- rtl821x_write_page(phydev, 0xa6d); +- ret = __phy_read(phydev, 0x10); +- rtl821x_write_page(phydev, 0); +- } +- +- return ret; +-} +- +-static int rtl822x_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, +- u16 val) +-{ +- int ret = rtlgen_write_mmd(phydev, devnum, regnum, val); +- +- if (ret != -EOPNOTSUPP) +- return ret; +- +- if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) { +- rtl821x_write_page(phydev, 0xa6d); +- ret = __phy_write(phydev, 0x12, val); +- rtl821x_write_page(phydev, 0); +- } +- +- return ret; +-} +- +-static int rtl822xb_config_init(struct phy_device *phydev) +-{ +- bool has_2500, has_sgmii; +- u16 mode; +- int ret; +- +- has_2500 = test_bit(PHY_INTERFACE_MODE_2500BASEX, +- phydev->host_interfaces) || +- phydev->interface == PHY_INTERFACE_MODE_2500BASEX; +- +- has_sgmii = test_bit(PHY_INTERFACE_MODE_SGMII, +- phydev->host_interfaces) || +- phydev->interface == PHY_INTERFACE_MODE_SGMII; +- +- /* fill in possible interfaces */ +- __assign_bit(PHY_INTERFACE_MODE_2500BASEX, phydev->possible_interfaces, +- has_2500); +- __assign_bit(PHY_INTERFACE_MODE_SGMII, phydev->possible_interfaces, +- has_sgmii); +- +- if (!has_2500 && !has_sgmii) +- return 0; +- +- /* determine SerDes option mode */ +- if (has_2500 && !has_sgmii) { +- mode = RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX; +- phydev->rate_matching = RATE_MATCH_PAUSE; +- } else { +- mode = RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII; +- phydev->rate_matching = RATE_MATCH_NONE; +- } +- +- /* the following sequence with magic numbers sets up the SerDes +- * option mode +- */ +- ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x75f3, 0); +- if (ret < 0) +- return ret; +- +- ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND1, +- RTL822X_VND1_SERDES_OPTION, +- RTL822X_VND1_SERDES_OPTION_MODE_MASK, +- mode); +- if (ret < 0) +- return ret; +- +- ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6a04, 0x0503); +- if (ret < 0) +- return ret; +- +- ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f10, 0xd455); +- if (ret < 0) +- return ret; +- +- return phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f11, 0x8020); +-} +- +-static int rtl822xb_get_rate_matching(struct phy_device *phydev, +- phy_interface_t iface) +-{ +- int val; +- +- /* Only rate matching at 2500base-x */ +- if (iface != PHY_INTERFACE_MODE_2500BASEX) +- return RATE_MATCH_NONE; +- +- val = phy_read_mmd(phydev, MDIO_MMD_VEND1, RTL822X_VND1_SERDES_OPTION); +- if (val < 0) +- return val; +- +- if ((val & RTL822X_VND1_SERDES_OPTION_MODE_MASK) == +- RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX) +- return RATE_MATCH_PAUSE; +- +- /* RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII */ +- return RATE_MATCH_NONE; +-} +- +-static int rtl822x_get_features(struct phy_device *phydev) +-{ +- int val; +- +- val = phy_read_paged(phydev, 0xa61, 0x13); +- if (val < 0) +- return val; +- +- linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, +- phydev->supported, val & MDIO_PMA_SPEED_2_5G); +- linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, +- phydev->supported, val & MDIO_PMA_SPEED_5G); +- linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, +- phydev->supported, val & MDIO_SPEED_10G); +- +- return genphy_read_abilities(phydev); +-} +- +-static int rtl822x_config_aneg(struct phy_device *phydev) +-{ +- int ret = 0; +- +- if (phydev->autoneg == AUTONEG_ENABLE) { +- u16 adv = linkmode_adv_to_mii_10gbt_adv_t(phydev->advertising); +- +- ret = phy_modify_paged_changed(phydev, 0xa5d, 0x12, +- MDIO_AN_10GBT_CTRL_ADV2_5G | +- MDIO_AN_10GBT_CTRL_ADV5G, +- adv); +- if (ret < 0) +- return ret; +- } +- +- return __genphy_config_aneg(phydev, ret); +-} +- +-static void rtl822xb_update_interface(struct phy_device *phydev) +-{ +- int val; +- +- if (!phydev->link) +- return; +- +- /* Change interface according to serdes mode */ +- val = phy_read_mmd(phydev, MDIO_MMD_VEND1, RTL822X_VND1_SERDES_CTRL3); +- if (val < 0) +- return; +- +- switch (val & RTL822X_VND1_SERDES_CTRL3_MODE_MASK) { +- case RTL822X_VND1_SERDES_CTRL3_MODE_2500BASEX: +- phydev->interface = PHY_INTERFACE_MODE_2500BASEX; +- break; +- case RTL822X_VND1_SERDES_CTRL3_MODE_SGMII: +- phydev->interface = PHY_INTERFACE_MODE_SGMII; +- break; +- } +-} +- +-static int rtl822x_read_status(struct phy_device *phydev) +-{ +- int lpadv, ret; +- +- mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, 0); +- +- ret = rtlgen_read_status(phydev); +- if (ret < 0) +- return ret; +- +- if (phydev->autoneg == AUTONEG_DISABLE || +- !phydev->autoneg_complete) +- return 0; +- +- lpadv = phy_read_paged(phydev, 0xa5d, 0x13); +- if (lpadv < 0) +- return lpadv; +- +- mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, lpadv); +- +- return 0; +-} +- +-static int rtl822xb_read_status(struct phy_device *phydev) +-{ +- int ret; +- +- ret = rtl822x_read_status(phydev); +- if (ret < 0) +- return ret; +- +- rtl822xb_update_interface(phydev); +- +- return 0; +-} +- +-static int rtl822x_c45_get_features(struct phy_device *phydev) +-{ +- linkmode_set_bit(ETHTOOL_LINK_MODE_TP_BIT, +- phydev->supported); +- +- return genphy_c45_pma_read_abilities(phydev); +-} +- +-static int rtl822x_c45_config_aneg(struct phy_device *phydev) +-{ +- bool changed = false; +- int ret, val; +- +- if (phydev->autoneg == AUTONEG_DISABLE) +- return genphy_c45_pma_setup_forced(phydev); +- +- ret = genphy_c45_an_config_aneg(phydev); +- if (ret < 0) +- return ret; +- if (ret > 0) +- changed = true; +- +- val = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising); +- +- /* Vendor register as C45 has no standardized support for 1000BaseT */ +- ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, RTL822X_VND2_GBCR, +- ADVERTISE_1000FULL, val); +- if (ret < 0) +- return ret; +- if (ret > 0) +- changed = true; +- +- return genphy_c45_check_and_restart_aneg(phydev, changed); +-} +- +-static int rtl822x_c45_read_status(struct phy_device *phydev) +-{ +- int ret, val; +- +- /* Vendor register as C45 has no standardized support for 1000BaseT */ +- if (phydev->autoneg == AUTONEG_ENABLE && genphy_c45_aneg_done(phydev)) { +- val = phy_read_mmd(phydev, MDIO_MMD_VEND2, +- RTL822X_VND2_GANLPAR); +- if (val < 0) +- return val; +- } else { +- val = 0; +- } +- mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, val); +- +- ret = genphy_c45_read_status(phydev); +- if (ret < 0) +- return ret; +- +- if (!phydev->link) { +- phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN; +- return 0; +- } +- +- /* Read actual speed from vendor register. */ +- val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL_VND2_PHYSR); +- if (val < 0) +- return val; +- +- rtlgen_decode_physr(phydev, val); +- +- return 0; +-} +- +-static int rtl822xb_c45_read_status(struct phy_device *phydev) +-{ +- int ret; +- +- ret = rtl822x_c45_read_status(phydev); +- if (ret < 0) +- return ret; +- +- rtl822xb_update_interface(phydev); +- +- return 0; +-} +- +-static bool rtlgen_supports_2_5gbps(struct phy_device *phydev) +-{ +- int val; +- +- phy_write(phydev, RTL821x_PAGE_SELECT, 0xa61); +- val = phy_read(phydev, 0x13); +- phy_write(phydev, RTL821x_PAGE_SELECT, 0); +- +- return val >= 0 && val & MDIO_PMA_SPEED_2_5G; +-} +- +-/* On internal PHY's MMD reads over C22 always return 0. +- * Check a MMD register which is known to be non-zero. +- */ +-static bool rtlgen_supports_mmd(struct phy_device *phydev) +-{ +- int val; +- +- phy_lock_mdio_bus(phydev); +- __phy_write(phydev, MII_MMD_CTRL, MDIO_MMD_PCS); +- __phy_write(phydev, MII_MMD_DATA, MDIO_PCS_EEE_ABLE); +- __phy_write(phydev, MII_MMD_CTRL, MDIO_MMD_PCS | MII_MMD_CTRL_NOINCR); +- val = __phy_read(phydev, MII_MMD_DATA); +- phy_unlock_mdio_bus(phydev); +- +- return val > 0; +-} +- +-static int rtlgen_match_phy_device(struct phy_device *phydev) +-{ +- return phydev->phy_id == RTL_GENERIC_PHYID && +- !rtlgen_supports_2_5gbps(phydev); +-} +- +-static int rtl8226_match_phy_device(struct phy_device *phydev) +-{ +- return phydev->phy_id == RTL_GENERIC_PHYID && +- rtlgen_supports_2_5gbps(phydev) && +- rtlgen_supports_mmd(phydev); +-} +- +-static int rtlgen_is_c45_match(struct phy_device *phydev, unsigned int id, +- bool is_c45) +-{ +- if (phydev->is_c45) +- return is_c45 && (id == phydev->c45_ids.device_ids[1]); +- else +- return !is_c45 && (id == phydev->phy_id); +-} +- +-static int rtl8221b_match_phy_device(struct phy_device *phydev) +-{ +- return phydev->phy_id == RTL_8221B && rtlgen_supports_mmd(phydev); +-} +- +-static int rtl8221b_vb_cg_c22_match_phy_device(struct phy_device *phydev) +-{ +- return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, false); +-} +- +-static int rtl8221b_vb_cg_c45_match_phy_device(struct phy_device *phydev) +-{ +- return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, true); +-} +- +-static int rtl8221b_vn_cg_c22_match_phy_device(struct phy_device *phydev) +-{ +- return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, false); +-} +- +-static int rtl8221b_vn_cg_c45_match_phy_device(struct phy_device *phydev) +-{ +- return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, true); +-} +- +-static int rtl_internal_nbaset_match_phy_device(struct phy_device *phydev) +-{ +- if (phydev->is_c45) +- return false; +- +- switch (phydev->phy_id) { +- case RTL_GENERIC_PHYID: +- case RTL_8221B: +- case RTL_8251B: +- case 0x001cc841: +- break; +- default: +- return false; +- } +- +- return rtlgen_supports_2_5gbps(phydev) && !rtlgen_supports_mmd(phydev); +-} +- +-static int rtl8251b_c45_match_phy_device(struct phy_device *phydev) +-{ +- return rtlgen_is_c45_match(phydev, RTL_8251B, true); +-} +- +-static int rtlgen_resume(struct phy_device *phydev) +-{ +- int ret = genphy_resume(phydev); +- +- /* Internal PHY's from RTL8168h up may not be instantly ready */ +- msleep(20); +- +- return ret; +-} +- +-static int rtlgen_c45_resume(struct phy_device *phydev) +-{ +- int ret = genphy_c45_pma_resume(phydev); +- +- msleep(20); +- +- return ret; +-} +- +-static int rtl9000a_config_init(struct phy_device *phydev) +-{ +- phydev->autoneg = AUTONEG_DISABLE; +- phydev->speed = SPEED_100; +- phydev->duplex = DUPLEX_FULL; +- +- return 0; +-} +- +-static int rtl9000a_config_aneg(struct phy_device *phydev) +-{ +- int ret; +- u16 ctl = 0; +- +- switch (phydev->master_slave_set) { +- case MASTER_SLAVE_CFG_MASTER_FORCE: +- ctl |= CTL1000_AS_MASTER; +- break; +- case MASTER_SLAVE_CFG_SLAVE_FORCE: +- break; +- case MASTER_SLAVE_CFG_UNKNOWN: +- case MASTER_SLAVE_CFG_UNSUPPORTED: +- return 0; +- default: +- phydev_warn(phydev, "Unsupported Master/Slave mode\n"); +- return -EOPNOTSUPP; +- } +- +- ret = phy_modify_changed(phydev, MII_CTRL1000, CTL1000_AS_MASTER, ctl); +- if (ret == 1) +- ret = genphy_soft_reset(phydev); +- +- return ret; +-} +- +-static int rtl9000a_read_status(struct phy_device *phydev) +-{ +- int ret; +- +- phydev->master_slave_get = MASTER_SLAVE_CFG_UNKNOWN; +- phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN; +- +- ret = genphy_update_link(phydev); +- if (ret) +- return ret; +- +- ret = phy_read(phydev, MII_CTRL1000); +- if (ret < 0) +- return ret; +- if (ret & CTL1000_AS_MASTER) +- phydev->master_slave_get = MASTER_SLAVE_CFG_MASTER_FORCE; +- else +- phydev->master_slave_get = MASTER_SLAVE_CFG_SLAVE_FORCE; +- +- ret = phy_read(phydev, MII_STAT1000); +- if (ret < 0) +- return ret; +- if (ret & LPA_1000MSRES) +- phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER; +- else +- phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE; +- +- return 0; +-} +- +-static int rtl9000a_ack_interrupt(struct phy_device *phydev) +-{ +- int err; +- +- err = phy_read(phydev, RTL8211F_INSR); +- +- return (err < 0) ? err : 0; +-} +- +-static int rtl9000a_config_intr(struct phy_device *phydev) +-{ +- u16 val; +- int err; +- +- if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { +- err = rtl9000a_ack_interrupt(phydev); +- if (err) +- return err; +- +- val = (u16)~RTL9000A_GINMR_LINK_STATUS; +- err = phy_write_paged(phydev, 0xa42, RTL9000A_GINMR, val); +- } else { +- val = ~0; +- err = phy_write_paged(phydev, 0xa42, RTL9000A_GINMR, val); +- if (err) +- return err; +- +- err = rtl9000a_ack_interrupt(phydev); +- } +- +- return phy_write_paged(phydev, 0xa42, RTL9000A_GINMR, val); +-} +- +-static irqreturn_t rtl9000a_handle_interrupt(struct phy_device *phydev) +-{ +- int irq_status; +- +- irq_status = phy_read(phydev, RTL8211F_INSR); +- if (irq_status < 0) { +- phy_error(phydev); +- return IRQ_NONE; +- } +- +- if (!(irq_status & RTL8211F_INER_LINK_STATUS)) +- return IRQ_NONE; +- +- phy_trigger_machine(phydev); +- +- return IRQ_HANDLED; +-} +- +-static struct phy_driver realtek_drvs[] = { +- { +- PHY_ID_MATCH_EXACT(0x00008201), +- .name = "RTL8201CP Ethernet", +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- }, { +- PHY_ID_MATCH_EXACT(0x001cc816), +- .name = "RTL8201F Fast Ethernet", +- .config_intr = &rtl8201_config_intr, +- .handle_interrupt = rtl8201_handle_interrupt, +- .suspend = genphy_suspend, +- .resume = genphy_resume, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- }, { +- PHY_ID_MATCH_MODEL(0x001cc880), +- .name = "RTL8208 Fast Ethernet", +- .read_mmd = genphy_read_mmd_unsupported, +- .write_mmd = genphy_write_mmd_unsupported, +- .suspend = genphy_suspend, +- .resume = genphy_resume, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- }, { +- PHY_ID_MATCH_EXACT(0x001cc910), +- .name = "RTL8211 Gigabit Ethernet", +- .config_aneg = rtl8211_config_aneg, +- .read_mmd = &genphy_read_mmd_unsupported, +- .write_mmd = &genphy_write_mmd_unsupported, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- }, { +- PHY_ID_MATCH_EXACT(0x001cc912), +- .name = "RTL8211B Gigabit Ethernet", +- .config_intr = &rtl8211b_config_intr, +- .handle_interrupt = rtl821x_handle_interrupt, +- .read_mmd = &genphy_read_mmd_unsupported, +- .write_mmd = &genphy_write_mmd_unsupported, +- .suspend = rtl8211b_suspend, +- .resume = rtl8211b_resume, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- }, { +- PHY_ID_MATCH_EXACT(0x001cc913), +- .name = "RTL8211C Gigabit Ethernet", +- .config_init = rtl8211c_config_init, +- .read_mmd = &genphy_read_mmd_unsupported, +- .write_mmd = &genphy_write_mmd_unsupported, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- }, { +- PHY_ID_MATCH_EXACT(0x001cc914), +- .name = "RTL8211DN Gigabit Ethernet", +- .config_intr = rtl8211e_config_intr, +- .handle_interrupt = rtl821x_handle_interrupt, +- .suspend = genphy_suspend, +- .resume = genphy_resume, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- }, { +- PHY_ID_MATCH_EXACT(0x001cc915), +- .name = "RTL8211E Gigabit Ethernet", +- .config_init = &rtl8211e_config_init, +- .config_intr = &rtl8211e_config_intr, +- .handle_interrupt = rtl821x_handle_interrupt, +- .suspend = genphy_suspend, +- .resume = genphy_resume, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- }, { +- PHY_ID_MATCH_EXACT(0x001cc916), +- .name = "RTL8211F Gigabit Ethernet", +- .probe = rtl821x_probe, +- .config_init = &rtl8211f_config_init, +- .read_status = rtlgen_read_status, +- .config_intr = &rtl8211f_config_intr, +- .handle_interrupt = rtl8211f_handle_interrupt, +- .suspend = rtl821x_suspend, +- .resume = rtl821x_resume, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- .flags = PHY_ALWAYS_CALL_SUSPEND, +- .led_hw_is_supported = rtl8211f_led_hw_is_supported, +- .led_hw_control_get = rtl8211f_led_hw_control_get, +- .led_hw_control_set = rtl8211f_led_hw_control_set, +- }, { +- PHY_ID_MATCH_EXACT(RTL_8211FVD_PHYID), +- .name = "RTL8211F-VD Gigabit Ethernet", +- .probe = rtl821x_probe, +- .config_init = &rtl8211f_config_init, +- .read_status = rtlgen_read_status, +- .config_intr = &rtl8211f_config_intr, +- .handle_interrupt = rtl8211f_handle_interrupt, +- .suspend = rtl821x_suspend, +- .resume = rtl821x_resume, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- .flags = PHY_ALWAYS_CALL_SUSPEND, +- }, { +- .name = "Generic FE-GE Realtek PHY", +- .match_phy_device = rtlgen_match_phy_device, +- .read_status = rtlgen_read_status, +- .suspend = genphy_suspend, +- .resume = rtlgen_resume, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- .read_mmd = rtlgen_read_mmd, +- .write_mmd = rtlgen_write_mmd, +- }, { +- .name = "RTL8226 2.5Gbps PHY", +- .match_phy_device = rtl8226_match_phy_device, +- .get_features = rtl822x_get_features, +- .config_aneg = rtl822x_config_aneg, +- .read_status = rtl822x_read_status, +- .suspend = genphy_suspend, +- .resume = rtlgen_resume, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- }, { +- .match_phy_device = rtl8221b_match_phy_device, +- .name = "RTL8226B_RTL8221B 2.5Gbps PHY", +- .get_features = rtl822x_get_features, +- .config_aneg = rtl822x_config_aneg, +- .config_init = rtl822xb_config_init, +- .get_rate_matching = rtl822xb_get_rate_matching, +- .read_status = rtl822xb_read_status, +- .suspend = genphy_suspend, +- .resume = rtlgen_resume, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- }, { +- PHY_ID_MATCH_EXACT(0x001cc838), +- .name = "RTL8226-CG 2.5Gbps PHY", +- .get_features = rtl822x_get_features, +- .config_aneg = rtl822x_config_aneg, +- .read_status = rtl822x_read_status, +- .suspend = genphy_suspend, +- .resume = rtlgen_resume, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- }, { +- PHY_ID_MATCH_EXACT(0x001cc848), +- .name = "RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY", +- .get_features = rtl822x_get_features, +- .config_aneg = rtl822x_config_aneg, +- .config_init = rtl822xb_config_init, +- .get_rate_matching = rtl822xb_get_rate_matching, +- .read_status = rtl822xb_read_status, +- .suspend = genphy_suspend, +- .resume = rtlgen_resume, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- }, { +- .match_phy_device = rtl8221b_vb_cg_c22_match_phy_device, +- .name = "RTL8221B-VB-CG 2.5Gbps PHY (C22)", +- .get_features = rtl822x_get_features, +- .config_aneg = rtl822x_config_aneg, +- .config_init = rtl822xb_config_init, +- .get_rate_matching = rtl822xb_get_rate_matching, +- .read_status = rtl822xb_read_status, +- .suspend = genphy_suspend, +- .resume = rtlgen_resume, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- }, { +- .match_phy_device = rtl8221b_vb_cg_c45_match_phy_device, +- .name = "RTL8221B-VB-CG 2.5Gbps PHY (C45)", +- .config_init = rtl822xb_config_init, +- .get_rate_matching = rtl822xb_get_rate_matching, +- .get_features = rtl822x_c45_get_features, +- .config_aneg = rtl822x_c45_config_aneg, +- .read_status = rtl822xb_c45_read_status, +- .suspend = genphy_c45_pma_suspend, +- .resume = rtlgen_c45_resume, +- }, { +- .match_phy_device = rtl8221b_vn_cg_c22_match_phy_device, +- .name = "RTL8221B-VM-CG 2.5Gbps PHY (C22)", +- .get_features = rtl822x_get_features, +- .config_aneg = rtl822x_config_aneg, +- .config_init = rtl822xb_config_init, +- .get_rate_matching = rtl822xb_get_rate_matching, +- .read_status = rtl822xb_read_status, +- .suspend = genphy_suspend, +- .resume = rtlgen_resume, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- }, { +- .match_phy_device = rtl8221b_vn_cg_c45_match_phy_device, +- .name = "RTL8221B-VN-CG 2.5Gbps PHY (C45)", +- .config_init = rtl822xb_config_init, +- .get_rate_matching = rtl822xb_get_rate_matching, +- .get_features = rtl822x_c45_get_features, +- .config_aneg = rtl822x_c45_config_aneg, +- .read_status = rtl822xb_c45_read_status, +- .suspend = genphy_c45_pma_suspend, +- .resume = rtlgen_c45_resume, +- }, { +- .match_phy_device = rtl8251b_c45_match_phy_device, +- .name = "RTL8251B 5Gbps PHY", +- .get_features = rtl822x_get_features, +- .config_aneg = rtl822x_config_aneg, +- .read_status = rtl822x_read_status, +- .suspend = genphy_suspend, +- .resume = rtlgen_resume, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- }, { +- .match_phy_device = rtl_internal_nbaset_match_phy_device, +- .name = "Realtek Internal NBASE-T PHY", +- .flags = PHY_IS_INTERNAL, +- .get_features = rtl822x_get_features, +- .config_aneg = rtl822x_config_aneg, +- .read_status = rtl822x_read_status, +- .suspend = genphy_suspend, +- .resume = rtlgen_resume, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- .read_mmd = rtl822x_read_mmd, +- .write_mmd = rtl822x_write_mmd, +- }, { +- PHY_ID_MATCH_EXACT(0x001ccad0), +- .name = "RTL8224 2.5Gbps PHY", +- .get_features = rtl822x_c45_get_features, +- .config_aneg = rtl822x_c45_config_aneg, +- .read_status = rtl822x_c45_read_status, +- .suspend = genphy_c45_pma_suspend, +- .resume = rtlgen_c45_resume, +- }, { +- PHY_ID_MATCH_EXACT(0x001cc961), +- .name = "RTL8366RB Gigabit Ethernet", +- .config_init = &rtl8366rb_config_init, +- /* These interrupts are handled by the irq controller +- * embedded inside the RTL8366RB, they get unmasked when the +- * irq is requested and ACKed by reading the status register, +- * which is done by the irqchip code. +- */ +- .config_intr = genphy_no_config_intr, +- .handle_interrupt = genphy_handle_interrupt_no_ack, +- .suspend = genphy_suspend, +- .resume = genphy_resume, +- }, { +- PHY_ID_MATCH_EXACT(0x001ccb00), +- .name = "RTL9000AA_RTL9000AN Ethernet", +- .features = PHY_BASIC_T1_FEATURES, +- .config_init = rtl9000a_config_init, +- .config_aneg = rtl9000a_config_aneg, +- .read_status = rtl9000a_read_status, +- .config_intr = rtl9000a_config_intr, +- .handle_interrupt = rtl9000a_handle_interrupt, +- .suspend = genphy_suspend, +- .resume = genphy_resume, +- .read_page = rtl821x_read_page, +- .write_page = rtl821x_write_page, +- }, { +- PHY_ID_MATCH_EXACT(0x001cc942), +- .name = "RTL8365MB-VC Gigabit Ethernet", +- /* Interrupt handling analogous to RTL8366RB */ +- .config_intr = genphy_no_config_intr, +- .handle_interrupt = genphy_handle_interrupt_no_ack, +- .suspend = genphy_suspend, +- .resume = genphy_resume, +- }, { +- PHY_ID_MATCH_EXACT(0x001cc960), +- .name = "RTL8366S Gigabit Ethernet", +- .suspend = genphy_suspend, +- .resume = genphy_resume, +- .read_mmd = genphy_read_mmd_unsupported, +- .write_mmd = genphy_write_mmd_unsupported, +- }, +-}; +- +-module_phy_driver(realtek_drvs); +- +-static const struct mdio_device_id __maybe_unused realtek_tbl[] = { +- { PHY_ID_MATCH_VENDOR(0x001cc800) }, +- { } +-}; +- +-MODULE_DEVICE_TABLE(mdio, realtek_tbl); +--- /dev/null ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -0,0 +1,1589 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* drivers/net/phy/realtek.c ++ * ++ * Driver for Realtek PHYs ++ * ++ * Author: Johnson Leung ++ * ++ * Copyright (c) 2004 Freescale Semiconductor, Inc. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define RTL821x_PHYSR 0x11 ++#define RTL821x_PHYSR_DUPLEX BIT(13) ++#define RTL821x_PHYSR_SPEED GENMASK(15, 14) ++ ++#define RTL821x_INER 0x12 ++#define RTL8211B_INER_INIT 0x6400 ++#define RTL8211E_INER_LINK_STATUS BIT(10) ++#define RTL8211F_INER_LINK_STATUS BIT(4) ++ ++#define RTL821x_INSR 0x13 ++ ++#define RTL821x_EXT_PAGE_SELECT 0x1e ++#define RTL821x_PAGE_SELECT 0x1f ++ ++#define RTL8211F_PHYCR1 0x18 ++#define RTL8211F_PHYCR2 0x19 ++#define RTL8211F_INSR 0x1d ++ ++#define RTL8211F_LEDCR 0x10 ++#define RTL8211F_LEDCR_MODE BIT(15) ++#define RTL8211F_LEDCR_ACT_TXRX BIT(4) ++#define RTL8211F_LEDCR_LINK_1000 BIT(3) ++#define RTL8211F_LEDCR_LINK_100 BIT(1) ++#define RTL8211F_LEDCR_LINK_10 BIT(0) ++#define RTL8211F_LEDCR_MASK GENMASK(4, 0) ++#define RTL8211F_LEDCR_SHIFT 5 ++ ++#define RTL8211F_TX_DELAY BIT(8) ++#define RTL8211F_RX_DELAY BIT(3) ++ ++#define RTL8211F_ALDPS_PLL_OFF BIT(1) ++#define RTL8211F_ALDPS_ENABLE BIT(2) ++#define RTL8211F_ALDPS_XTAL_OFF BIT(12) ++ ++#define RTL8211E_CTRL_DELAY BIT(13) ++#define RTL8211E_TX_DELAY BIT(12) ++#define RTL8211E_RX_DELAY BIT(11) ++ ++#define RTL8211F_CLKOUT_EN BIT(0) ++ ++#define RTL8201F_ISR 0x1e ++#define RTL8201F_ISR_ANERR BIT(15) ++#define RTL8201F_ISR_DUPLEX BIT(13) ++#define RTL8201F_ISR_LINK BIT(11) ++#define RTL8201F_ISR_MASK (RTL8201F_ISR_ANERR | \ ++ RTL8201F_ISR_DUPLEX | \ ++ RTL8201F_ISR_LINK) ++#define RTL8201F_IER 0x13 ++ ++#define RTL822X_VND1_SERDES_OPTION 0x697a ++#define RTL822X_VND1_SERDES_OPTION_MODE_MASK GENMASK(5, 0) ++#define RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII 0 ++#define RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX 2 ++ ++#define RTL822X_VND1_SERDES_CTRL3 0x7580 ++#define RTL822X_VND1_SERDES_CTRL3_MODE_MASK GENMASK(5, 0) ++#define RTL822X_VND1_SERDES_CTRL3_MODE_SGMII 0x02 ++#define RTL822X_VND1_SERDES_CTRL3_MODE_2500BASEX 0x16 ++ ++/* RTL822X_VND2_XXXXX registers are only accessible when phydev->is_c45 ++ * is set, they cannot be accessed by C45-over-C22. ++ */ ++#define RTL822X_VND2_GBCR 0xa412 ++ ++#define RTL822X_VND2_GANLPAR 0xa414 ++ ++#define RTL8366RB_POWER_SAVE 0x15 ++#define RTL8366RB_POWER_SAVE_ON BIT(12) ++ ++#define RTL9000A_GINMR 0x14 ++#define RTL9000A_GINMR_LINK_STATUS BIT(4) ++ ++#define RTL_VND2_PHYSR 0xa434 ++#define RTL_VND2_PHYSR_DUPLEX BIT(3) ++#define RTL_VND2_PHYSR_SPEEDL GENMASK(5, 4) ++#define RTL_VND2_PHYSR_SPEEDH GENMASK(10, 9) ++#define RTL_VND2_PHYSR_MASTER BIT(11) ++#define RTL_VND2_PHYSR_SPEED_MASK (RTL_VND2_PHYSR_SPEEDL | RTL_VND2_PHYSR_SPEEDH) ++ ++#define RTL_GENERIC_PHYID 0x001cc800 ++#define RTL_8211FVD_PHYID 0x001cc878 ++#define RTL_8221B 0x001cc840 ++#define RTL_8221B_VB_CG 0x001cc849 ++#define RTL_8221B_VN_CG 0x001cc84a ++#define RTL_8251B 0x001cc862 ++ ++#define RTL8211F_LED_COUNT 3 ++ ++MODULE_DESCRIPTION("Realtek PHY driver"); ++MODULE_AUTHOR("Johnson Leung"); ++MODULE_LICENSE("GPL"); ++ ++struct rtl821x_priv { ++ u16 phycr1; ++ u16 phycr2; ++ bool has_phycr2; ++ struct clk *clk; ++}; ++ ++static int rtl821x_read_page(struct phy_device *phydev) ++{ ++ return __phy_read(phydev, RTL821x_PAGE_SELECT); ++} ++ ++static int rtl821x_write_page(struct phy_device *phydev, int page) ++{ ++ return __phy_write(phydev, RTL821x_PAGE_SELECT, page); ++} ++ ++static int rtl821x_probe(struct phy_device *phydev) ++{ ++ struct device *dev = &phydev->mdio.dev; ++ struct rtl821x_priv *priv; ++ u32 phy_id = phydev->drv->phy_id; ++ int ret; ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->clk = devm_clk_get_optional_enabled(dev, NULL); ++ if (IS_ERR(priv->clk)) ++ return dev_err_probe(dev, PTR_ERR(priv->clk), ++ "failed to get phy clock\n"); ++ ++ ret = phy_read_paged(phydev, 0xa43, RTL8211F_PHYCR1); ++ if (ret < 0) ++ return ret; ++ ++ priv->phycr1 = ret & (RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF); ++ if (of_property_read_bool(dev->of_node, "realtek,aldps-enable")) ++ priv->phycr1 |= RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF; ++ ++ priv->has_phycr2 = !(phy_id == RTL_8211FVD_PHYID); ++ if (priv->has_phycr2) { ++ ret = phy_read_paged(phydev, 0xa43, RTL8211F_PHYCR2); ++ if (ret < 0) ++ return ret; ++ ++ priv->phycr2 = ret & RTL8211F_CLKOUT_EN; ++ if (of_property_read_bool(dev->of_node, "realtek,clkout-disable")) ++ priv->phycr2 &= ~RTL8211F_CLKOUT_EN; ++ } ++ ++ phydev->priv = priv; ++ ++ return 0; ++} ++ ++static int rtl8201_ack_interrupt(struct phy_device *phydev) ++{ ++ int err; ++ ++ err = phy_read(phydev, RTL8201F_ISR); ++ ++ return (err < 0) ? err : 0; ++} ++ ++static int rtl821x_ack_interrupt(struct phy_device *phydev) ++{ ++ int err; ++ ++ err = phy_read(phydev, RTL821x_INSR); ++ ++ return (err < 0) ? err : 0; ++} ++ ++static int rtl8211f_ack_interrupt(struct phy_device *phydev) ++{ ++ int err; ++ ++ err = phy_read_paged(phydev, 0xa43, RTL8211F_INSR); ++ ++ return (err < 0) ? err : 0; ++} ++ ++static int rtl8201_config_intr(struct phy_device *phydev) ++{ ++ u16 val; ++ int err; ++ ++ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { ++ err = rtl8201_ack_interrupt(phydev); ++ if (err) ++ return err; ++ ++ val = BIT(13) | BIT(12) | BIT(11); ++ err = phy_write_paged(phydev, 0x7, RTL8201F_IER, val); ++ } else { ++ val = 0; ++ err = phy_write_paged(phydev, 0x7, RTL8201F_IER, val); ++ if (err) ++ return err; ++ ++ err = rtl8201_ack_interrupt(phydev); ++ } ++ ++ return err; ++} ++ ++static int rtl8211b_config_intr(struct phy_device *phydev) ++{ ++ int err; ++ ++ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { ++ err = rtl821x_ack_interrupt(phydev); ++ if (err) ++ return err; ++ ++ err = phy_write(phydev, RTL821x_INER, ++ RTL8211B_INER_INIT); ++ } else { ++ err = phy_write(phydev, RTL821x_INER, 0); ++ if (err) ++ return err; ++ ++ err = rtl821x_ack_interrupt(phydev); ++ } ++ ++ return err; ++} ++ ++static int rtl8211e_config_intr(struct phy_device *phydev) ++{ ++ int err; ++ ++ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { ++ err = rtl821x_ack_interrupt(phydev); ++ if (err) ++ return err; ++ ++ err = phy_write(phydev, RTL821x_INER, ++ RTL8211E_INER_LINK_STATUS); ++ } else { ++ err = phy_write(phydev, RTL821x_INER, 0); ++ if (err) ++ return err; ++ ++ err = rtl821x_ack_interrupt(phydev); ++ } ++ ++ return err; ++} ++ ++static int rtl8211f_config_intr(struct phy_device *phydev) ++{ ++ u16 val; ++ int err; ++ ++ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { ++ err = rtl8211f_ack_interrupt(phydev); ++ if (err) ++ return err; ++ ++ val = RTL8211F_INER_LINK_STATUS; ++ err = phy_write_paged(phydev, 0xa42, RTL821x_INER, val); ++ } else { ++ val = 0; ++ err = phy_write_paged(phydev, 0xa42, RTL821x_INER, val); ++ if (err) ++ return err; ++ ++ err = rtl8211f_ack_interrupt(phydev); ++ } ++ ++ return err; ++} ++ ++static irqreturn_t rtl8201_handle_interrupt(struct phy_device *phydev) ++{ ++ int irq_status; ++ ++ irq_status = phy_read(phydev, RTL8201F_ISR); ++ if (irq_status < 0) { ++ phy_error(phydev); ++ return IRQ_NONE; ++ } ++ ++ if (!(irq_status & RTL8201F_ISR_MASK)) ++ return IRQ_NONE; ++ ++ phy_trigger_machine(phydev); ++ ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t rtl821x_handle_interrupt(struct phy_device *phydev) ++{ ++ int irq_status, irq_enabled; ++ ++ irq_status = phy_read(phydev, RTL821x_INSR); ++ if (irq_status < 0) { ++ phy_error(phydev); ++ return IRQ_NONE; ++ } ++ ++ irq_enabled = phy_read(phydev, RTL821x_INER); ++ if (irq_enabled < 0) { ++ phy_error(phydev); ++ return IRQ_NONE; ++ } ++ ++ if (!(irq_status & irq_enabled)) ++ return IRQ_NONE; ++ ++ phy_trigger_machine(phydev); ++ ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t rtl8211f_handle_interrupt(struct phy_device *phydev) ++{ ++ int irq_status; ++ ++ irq_status = phy_read_paged(phydev, 0xa43, RTL8211F_INSR); ++ if (irq_status < 0) { ++ phy_error(phydev); ++ return IRQ_NONE; ++ } ++ ++ if (!(irq_status & RTL8211F_INER_LINK_STATUS)) ++ return IRQ_NONE; ++ ++ phy_trigger_machine(phydev); ++ ++ return IRQ_HANDLED; ++} ++ ++static int rtl8211_config_aneg(struct phy_device *phydev) ++{ ++ int ret; ++ ++ ret = genphy_config_aneg(phydev); ++ if (ret < 0) ++ return ret; ++ ++ /* Quirk was copied from vendor driver. Unfortunately it includes no ++ * description of the magic numbers. ++ */ ++ if (phydev->speed == SPEED_100 && phydev->autoneg == AUTONEG_DISABLE) { ++ phy_write(phydev, 0x17, 0x2138); ++ phy_write(phydev, 0x0e, 0x0260); ++ } else { ++ phy_write(phydev, 0x17, 0x2108); ++ phy_write(phydev, 0x0e, 0x0000); ++ } ++ ++ return 0; ++} ++ ++static int rtl8211c_config_init(struct phy_device *phydev) ++{ ++ /* RTL8211C has an issue when operating in Gigabit slave mode */ ++ return phy_set_bits(phydev, MII_CTRL1000, ++ CTL1000_ENABLE_MASTER | CTL1000_AS_MASTER); ++} ++ ++static int rtl8211f_config_init(struct phy_device *phydev) ++{ ++ struct rtl821x_priv *priv = phydev->priv; ++ struct device *dev = &phydev->mdio.dev; ++ u16 val_txdly, val_rxdly; ++ int ret; ++ ++ ret = phy_modify_paged_changed(phydev, 0xa43, RTL8211F_PHYCR1, ++ RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF, ++ priv->phycr1); ++ if (ret < 0) { ++ dev_err(dev, "aldps mode configuration failed: %pe\n", ++ ERR_PTR(ret)); ++ return ret; ++ } ++ ++ switch (phydev->interface) { ++ case PHY_INTERFACE_MODE_RGMII: ++ val_txdly = 0; ++ val_rxdly = 0; ++ break; ++ ++ case PHY_INTERFACE_MODE_RGMII_RXID: ++ val_txdly = 0; ++ val_rxdly = RTL8211F_RX_DELAY; ++ break; ++ ++ case PHY_INTERFACE_MODE_RGMII_TXID: ++ val_txdly = RTL8211F_TX_DELAY; ++ val_rxdly = 0; ++ break; ++ ++ case PHY_INTERFACE_MODE_RGMII_ID: ++ val_txdly = RTL8211F_TX_DELAY; ++ val_rxdly = RTL8211F_RX_DELAY; ++ break; ++ ++ default: /* the rest of the modes imply leaving delay as is. */ ++ return 0; ++ } ++ ++ ret = phy_modify_paged_changed(phydev, 0xd08, 0x11, RTL8211F_TX_DELAY, ++ val_txdly); ++ if (ret < 0) { ++ dev_err(dev, "Failed to update the TX delay register\n"); ++ return ret; ++ } else if (ret) { ++ dev_dbg(dev, ++ "%s 2ns TX delay (and changing the value from pin-strapping RXD1 or the bootloader)\n", ++ val_txdly ? "Enabling" : "Disabling"); ++ } else { ++ dev_dbg(dev, ++ "2ns TX delay was already %s (by pin-strapping RXD1 or bootloader configuration)\n", ++ val_txdly ? "enabled" : "disabled"); ++ } ++ ++ ret = phy_modify_paged_changed(phydev, 0xd08, 0x15, RTL8211F_RX_DELAY, ++ val_rxdly); ++ if (ret < 0) { ++ dev_err(dev, "Failed to update the RX delay register\n"); ++ return ret; ++ } else if (ret) { ++ dev_dbg(dev, ++ "%s 2ns RX delay (and changing the value from pin-strapping RXD0 or the bootloader)\n", ++ val_rxdly ? "Enabling" : "Disabling"); ++ } else { ++ dev_dbg(dev, ++ "2ns RX delay was already %s (by pin-strapping RXD0 or bootloader configuration)\n", ++ val_rxdly ? "enabled" : "disabled"); ++ } ++ ++ if (priv->has_phycr2) { ++ ret = phy_modify_paged(phydev, 0xa43, RTL8211F_PHYCR2, ++ RTL8211F_CLKOUT_EN, priv->phycr2); ++ if (ret < 0) { ++ dev_err(dev, "clkout configuration failed: %pe\n", ++ ERR_PTR(ret)); ++ return ret; ++ } ++ ++ return genphy_soft_reset(phydev); ++ } ++ ++ return 0; ++} ++ ++static int rtl821x_suspend(struct phy_device *phydev) ++{ ++ struct rtl821x_priv *priv = phydev->priv; ++ int ret = 0; ++ ++ if (!phydev->wol_enabled) { ++ ret = genphy_suspend(phydev); ++ ++ if (ret) ++ return ret; ++ ++ clk_disable_unprepare(priv->clk); ++ } ++ ++ return ret; ++} ++ ++static int rtl821x_resume(struct phy_device *phydev) ++{ ++ struct rtl821x_priv *priv = phydev->priv; ++ int ret; ++ ++ if (!phydev->wol_enabled) ++ clk_prepare_enable(priv->clk); ++ ++ ret = genphy_resume(phydev); ++ if (ret < 0) ++ return ret; ++ ++ msleep(20); ++ ++ return 0; ++} ++ ++static int rtl8211f_led_hw_is_supported(struct phy_device *phydev, u8 index, ++ unsigned long rules) ++{ ++ const unsigned long mask = BIT(TRIGGER_NETDEV_LINK_10) | ++ BIT(TRIGGER_NETDEV_LINK_100) | ++ BIT(TRIGGER_NETDEV_LINK_1000) | ++ BIT(TRIGGER_NETDEV_RX) | ++ BIT(TRIGGER_NETDEV_TX); ++ ++ /* The RTL8211F PHY supports these LED settings on up to three LEDs: ++ * - Link: Configurable subset of 10/100/1000 link rates ++ * - Active: Blink on activity, RX or TX is not differentiated ++ * The Active option has two modes, A and B: ++ * - A: Link and Active indication at configurable, but matching, ++ * subset of 10/100/1000 link rates ++ * - B: Link indication at configurable subset of 10/100/1000 link ++ * rates and Active indication always at all three 10+100+1000 ++ * link rates. ++ * This code currently uses mode B only. ++ */ ++ ++ if (index >= RTL8211F_LED_COUNT) ++ return -EINVAL; ++ ++ /* Filter out any other unsupported triggers. */ ++ if (rules & ~mask) ++ return -EOPNOTSUPP; ++ ++ /* RX and TX are not differentiated, either both are set or not set. */ ++ if (!(rules & BIT(TRIGGER_NETDEV_RX)) ^ !(rules & BIT(TRIGGER_NETDEV_TX))) ++ return -EOPNOTSUPP; ++ ++ return 0; ++} ++ ++static int rtl8211f_led_hw_control_get(struct phy_device *phydev, u8 index, ++ unsigned long *rules) ++{ ++ int val; ++ ++ if (index >= RTL8211F_LED_COUNT) ++ return -EINVAL; ++ ++ val = phy_read_paged(phydev, 0xd04, RTL8211F_LEDCR); ++ if (val < 0) ++ return val; ++ ++ val >>= RTL8211F_LEDCR_SHIFT * index; ++ val &= RTL8211F_LEDCR_MASK; ++ ++ if (val & RTL8211F_LEDCR_LINK_10) ++ set_bit(TRIGGER_NETDEV_LINK_10, rules); ++ ++ if (val & RTL8211F_LEDCR_LINK_100) ++ set_bit(TRIGGER_NETDEV_LINK_100, rules); ++ ++ if (val & RTL8211F_LEDCR_LINK_1000) ++ set_bit(TRIGGER_NETDEV_LINK_1000, rules); ++ ++ if (val & RTL8211F_LEDCR_ACT_TXRX) { ++ set_bit(TRIGGER_NETDEV_RX, rules); ++ set_bit(TRIGGER_NETDEV_TX, rules); ++ } ++ ++ return 0; ++} ++ ++static int rtl8211f_led_hw_control_set(struct phy_device *phydev, u8 index, ++ unsigned long rules) ++{ ++ const u16 mask = RTL8211F_LEDCR_MASK << (RTL8211F_LEDCR_SHIFT * index); ++ u16 reg = 0; ++ ++ if (index >= RTL8211F_LED_COUNT) ++ return -EINVAL; ++ ++ if (test_bit(TRIGGER_NETDEV_LINK_10, &rules)) ++ reg |= RTL8211F_LEDCR_LINK_10; ++ ++ if (test_bit(TRIGGER_NETDEV_LINK_100, &rules)) ++ reg |= RTL8211F_LEDCR_LINK_100; ++ ++ if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules)) ++ reg |= RTL8211F_LEDCR_LINK_1000; ++ ++ if (test_bit(TRIGGER_NETDEV_RX, &rules) || ++ test_bit(TRIGGER_NETDEV_TX, &rules)) { ++ reg |= RTL8211F_LEDCR_ACT_TXRX; ++ } ++ ++ reg <<= RTL8211F_LEDCR_SHIFT * index; ++ reg |= RTL8211F_LEDCR_MODE; /* Mode B */ ++ ++ return phy_modify_paged(phydev, 0xd04, RTL8211F_LEDCR, mask, reg); ++} ++ ++static int rtl8211e_config_init(struct phy_device *phydev) ++{ ++ int ret = 0, oldpage; ++ u16 val; ++ ++ /* enable TX/RX delay for rgmii-* modes, and disable them for rgmii. */ ++ switch (phydev->interface) { ++ case PHY_INTERFACE_MODE_RGMII: ++ val = RTL8211E_CTRL_DELAY | 0; ++ break; ++ case PHY_INTERFACE_MODE_RGMII_ID: ++ val = RTL8211E_CTRL_DELAY | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY; ++ break; ++ case PHY_INTERFACE_MODE_RGMII_RXID: ++ val = RTL8211E_CTRL_DELAY | RTL8211E_RX_DELAY; ++ break; ++ case PHY_INTERFACE_MODE_RGMII_TXID: ++ val = RTL8211E_CTRL_DELAY | RTL8211E_TX_DELAY; ++ break; ++ default: /* the rest of the modes imply leaving delays as is. */ ++ return 0; ++ } ++ ++ /* According to a sample driver there is a 0x1c config register on the ++ * 0xa4 extension page (0x7) layout. It can be used to disable/enable ++ * the RX/TX delays otherwise controlled by RXDLY/TXDLY pins. ++ * The configuration register definition: ++ * 14 = reserved ++ * 13 = Force Tx RX Delay controlled by bit12 bit11, ++ * 12 = RX Delay, 11 = TX Delay ++ * 10:0 = Test && debug settings reserved by realtek ++ */ ++ oldpage = phy_select_page(phydev, 0x7); ++ if (oldpage < 0) ++ goto err_restore_page; ++ ++ ret = __phy_write(phydev, RTL821x_EXT_PAGE_SELECT, 0xa4); ++ if (ret) ++ goto err_restore_page; ++ ++ ret = __phy_modify(phydev, 0x1c, RTL8211E_CTRL_DELAY ++ | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY, ++ val); ++ ++err_restore_page: ++ return phy_restore_page(phydev, oldpage, ret); ++} ++ ++static int rtl8211b_suspend(struct phy_device *phydev) ++{ ++ phy_write(phydev, MII_MMD_DATA, BIT(9)); ++ ++ return genphy_suspend(phydev); ++} ++ ++static int rtl8211b_resume(struct phy_device *phydev) ++{ ++ phy_write(phydev, MII_MMD_DATA, 0); ++ ++ return genphy_resume(phydev); ++} ++ ++static int rtl8366rb_config_init(struct phy_device *phydev) ++{ ++ int ret; ++ ++ ret = phy_set_bits(phydev, RTL8366RB_POWER_SAVE, ++ RTL8366RB_POWER_SAVE_ON); ++ if (ret) { ++ dev_err(&phydev->mdio.dev, ++ "error enabling power management\n"); ++ } ++ ++ return ret; ++} ++ ++/* get actual speed to cover the downshift case */ ++static void rtlgen_decode_physr(struct phy_device *phydev, int val) ++{ ++ /* bit 3 ++ * 0: Half Duplex ++ * 1: Full Duplex ++ */ ++ if (val & RTL_VND2_PHYSR_DUPLEX) ++ phydev->duplex = DUPLEX_FULL; ++ else ++ phydev->duplex = DUPLEX_HALF; ++ ++ switch (val & RTL_VND2_PHYSR_SPEED_MASK) { ++ case 0x0000: ++ phydev->speed = SPEED_10; ++ break; ++ case 0x0010: ++ phydev->speed = SPEED_100; ++ break; ++ case 0x0020: ++ phydev->speed = SPEED_1000; ++ break; ++ case 0x0200: ++ phydev->speed = SPEED_10000; ++ break; ++ case 0x0210: ++ phydev->speed = SPEED_2500; ++ break; ++ case 0x0220: ++ phydev->speed = SPEED_5000; ++ break; ++ default: ++ break; ++ } ++ ++ /* bit 11 ++ * 0: Slave Mode ++ * 1: Master Mode ++ */ ++ if (phydev->speed >= 1000) { ++ if (val & RTL_VND2_PHYSR_MASTER) ++ phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER; ++ else ++ phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE; ++ } else { ++ phydev->master_slave_state = MASTER_SLAVE_STATE_UNSUPPORTED; ++ } ++} ++ ++static int rtlgen_read_status(struct phy_device *phydev) ++{ ++ int ret, val; ++ ++ ret = genphy_read_status(phydev); ++ if (ret < 0) ++ return ret; ++ ++ if (!phydev->link) ++ return 0; ++ ++ val = phy_read_paged(phydev, 0xa43, 0x12); ++ if (val < 0) ++ return val; ++ ++ rtlgen_decode_physr(phydev, val); ++ ++ return 0; ++} ++ ++static int rtlgen_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) ++{ ++ int ret; ++ ++ if (devnum == MDIO_MMD_VEND2) { ++ rtl821x_write_page(phydev, regnum >> 4); ++ ret = __phy_read(phydev, 0x10 + ((regnum & 0xf) >> 1)); ++ rtl821x_write_page(phydev, 0); ++ } else if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) { ++ rtl821x_write_page(phydev, 0xa5c); ++ ret = __phy_read(phydev, 0x12); ++ rtl821x_write_page(phydev, 0); ++ } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) { ++ rtl821x_write_page(phydev, 0xa5d); ++ ret = __phy_read(phydev, 0x10); ++ rtl821x_write_page(phydev, 0); ++ } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE) { ++ rtl821x_write_page(phydev, 0xa5d); ++ ret = __phy_read(phydev, 0x11); ++ rtl821x_write_page(phydev, 0); ++ } else { ++ ret = -EOPNOTSUPP; ++ } ++ ++ return ret; ++} ++ ++static int rtlgen_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, ++ u16 val) ++{ ++ int ret; ++ ++ if (devnum == MDIO_MMD_VEND2) { ++ rtl821x_write_page(phydev, regnum >> 4); ++ ret = __phy_write(phydev, 0x10 + ((regnum & 0xf) >> 1), val); ++ rtl821x_write_page(phydev, 0); ++ } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) { ++ rtl821x_write_page(phydev, 0xa5d); ++ ret = __phy_write(phydev, 0x10, val); ++ rtl821x_write_page(phydev, 0); ++ } else { ++ ret = -EOPNOTSUPP; ++ } ++ ++ return ret; ++} ++ ++static int rtl822x_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) ++{ ++ int ret = rtlgen_read_mmd(phydev, devnum, regnum); ++ ++ if (ret != -EOPNOTSUPP) ++ return ret; ++ ++ if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE2) { ++ rtl821x_write_page(phydev, 0xa6e); ++ ret = __phy_read(phydev, 0x16); ++ rtl821x_write_page(phydev, 0); ++ } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) { ++ rtl821x_write_page(phydev, 0xa6d); ++ ret = __phy_read(phydev, 0x12); ++ rtl821x_write_page(phydev, 0); ++ } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE2) { ++ rtl821x_write_page(phydev, 0xa6d); ++ ret = __phy_read(phydev, 0x10); ++ rtl821x_write_page(phydev, 0); ++ } ++ ++ return ret; ++} ++ ++static int rtl822x_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, ++ u16 val) ++{ ++ int ret = rtlgen_write_mmd(phydev, devnum, regnum, val); ++ ++ if (ret != -EOPNOTSUPP) ++ return ret; ++ ++ if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) { ++ rtl821x_write_page(phydev, 0xa6d); ++ ret = __phy_write(phydev, 0x12, val); ++ rtl821x_write_page(phydev, 0); ++ } ++ ++ return ret; ++} ++ ++static int rtl822xb_config_init(struct phy_device *phydev) ++{ ++ bool has_2500, has_sgmii; ++ u16 mode; ++ int ret; ++ ++ has_2500 = test_bit(PHY_INTERFACE_MODE_2500BASEX, ++ phydev->host_interfaces) || ++ phydev->interface == PHY_INTERFACE_MODE_2500BASEX; ++ ++ has_sgmii = test_bit(PHY_INTERFACE_MODE_SGMII, ++ phydev->host_interfaces) || ++ phydev->interface == PHY_INTERFACE_MODE_SGMII; ++ ++ /* fill in possible interfaces */ ++ __assign_bit(PHY_INTERFACE_MODE_2500BASEX, phydev->possible_interfaces, ++ has_2500); ++ __assign_bit(PHY_INTERFACE_MODE_SGMII, phydev->possible_interfaces, ++ has_sgmii); ++ ++ if (!has_2500 && !has_sgmii) ++ return 0; ++ ++ /* determine SerDes option mode */ ++ if (has_2500 && !has_sgmii) { ++ mode = RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX; ++ phydev->rate_matching = RATE_MATCH_PAUSE; ++ } else { ++ mode = RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII; ++ phydev->rate_matching = RATE_MATCH_NONE; ++ } ++ ++ /* the following sequence with magic numbers sets up the SerDes ++ * option mode ++ */ ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x75f3, 0); ++ if (ret < 0) ++ return ret; ++ ++ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND1, ++ RTL822X_VND1_SERDES_OPTION, ++ RTL822X_VND1_SERDES_OPTION_MODE_MASK, ++ mode); ++ if (ret < 0) ++ return ret; ++ ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6a04, 0x0503); ++ if (ret < 0) ++ return ret; ++ ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f10, 0xd455); ++ if (ret < 0) ++ return ret; ++ ++ return phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f11, 0x8020); ++} ++ ++static int rtl822xb_get_rate_matching(struct phy_device *phydev, ++ phy_interface_t iface) ++{ ++ int val; ++ ++ /* Only rate matching at 2500base-x */ ++ if (iface != PHY_INTERFACE_MODE_2500BASEX) ++ return RATE_MATCH_NONE; ++ ++ val = phy_read_mmd(phydev, MDIO_MMD_VEND1, RTL822X_VND1_SERDES_OPTION); ++ if (val < 0) ++ return val; ++ ++ if ((val & RTL822X_VND1_SERDES_OPTION_MODE_MASK) == ++ RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX) ++ return RATE_MATCH_PAUSE; ++ ++ /* RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII */ ++ return RATE_MATCH_NONE; ++} ++ ++static int rtl822x_get_features(struct phy_device *phydev) ++{ ++ int val; ++ ++ val = phy_read_paged(phydev, 0xa61, 0x13); ++ if (val < 0) ++ return val; ++ ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, ++ phydev->supported, val & MDIO_PMA_SPEED_2_5G); ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, ++ phydev->supported, val & MDIO_PMA_SPEED_5G); ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, ++ phydev->supported, val & MDIO_SPEED_10G); ++ ++ return genphy_read_abilities(phydev); ++} ++ ++static int rtl822x_config_aneg(struct phy_device *phydev) ++{ ++ int ret = 0; ++ ++ if (phydev->autoneg == AUTONEG_ENABLE) { ++ u16 adv = linkmode_adv_to_mii_10gbt_adv_t(phydev->advertising); ++ ++ ret = phy_modify_paged_changed(phydev, 0xa5d, 0x12, ++ MDIO_AN_10GBT_CTRL_ADV2_5G | ++ MDIO_AN_10GBT_CTRL_ADV5G, ++ adv); ++ if (ret < 0) ++ return ret; ++ } ++ ++ return __genphy_config_aneg(phydev, ret); ++} ++ ++static void rtl822xb_update_interface(struct phy_device *phydev) ++{ ++ int val; ++ ++ if (!phydev->link) ++ return; ++ ++ /* Change interface according to serdes mode */ ++ val = phy_read_mmd(phydev, MDIO_MMD_VEND1, RTL822X_VND1_SERDES_CTRL3); ++ if (val < 0) ++ return; ++ ++ switch (val & RTL822X_VND1_SERDES_CTRL3_MODE_MASK) { ++ case RTL822X_VND1_SERDES_CTRL3_MODE_2500BASEX: ++ phydev->interface = PHY_INTERFACE_MODE_2500BASEX; ++ break; ++ case RTL822X_VND1_SERDES_CTRL3_MODE_SGMII: ++ phydev->interface = PHY_INTERFACE_MODE_SGMII; ++ break; ++ } ++} ++ ++static int rtl822x_read_status(struct phy_device *phydev) ++{ ++ int lpadv, ret; ++ ++ mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, 0); ++ ++ ret = rtlgen_read_status(phydev); ++ if (ret < 0) ++ return ret; ++ ++ if (phydev->autoneg == AUTONEG_DISABLE || ++ !phydev->autoneg_complete) ++ return 0; ++ ++ lpadv = phy_read_paged(phydev, 0xa5d, 0x13); ++ if (lpadv < 0) ++ return lpadv; ++ ++ mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, lpadv); ++ ++ return 0; ++} ++ ++static int rtl822xb_read_status(struct phy_device *phydev) ++{ ++ int ret; ++ ++ ret = rtl822x_read_status(phydev); ++ if (ret < 0) ++ return ret; ++ ++ rtl822xb_update_interface(phydev); ++ ++ return 0; ++} ++ ++static int rtl822x_c45_get_features(struct phy_device *phydev) ++{ ++ linkmode_set_bit(ETHTOOL_LINK_MODE_TP_BIT, ++ phydev->supported); ++ ++ return genphy_c45_pma_read_abilities(phydev); ++} ++ ++static int rtl822x_c45_config_aneg(struct phy_device *phydev) ++{ ++ bool changed = false; ++ int ret, val; ++ ++ if (phydev->autoneg == AUTONEG_DISABLE) ++ return genphy_c45_pma_setup_forced(phydev); ++ ++ ret = genphy_c45_an_config_aneg(phydev); ++ if (ret < 0) ++ return ret; ++ if (ret > 0) ++ changed = true; ++ ++ val = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising); ++ ++ /* Vendor register as C45 has no standardized support for 1000BaseT */ ++ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, RTL822X_VND2_GBCR, ++ ADVERTISE_1000FULL, val); ++ if (ret < 0) ++ return ret; ++ if (ret > 0) ++ changed = true; ++ ++ return genphy_c45_check_and_restart_aneg(phydev, changed); ++} ++ ++static int rtl822x_c45_read_status(struct phy_device *phydev) ++{ ++ int ret, val; ++ ++ /* Vendor register as C45 has no standardized support for 1000BaseT */ ++ if (phydev->autoneg == AUTONEG_ENABLE && genphy_c45_aneg_done(phydev)) { ++ val = phy_read_mmd(phydev, MDIO_MMD_VEND2, ++ RTL822X_VND2_GANLPAR); ++ if (val < 0) ++ return val; ++ } else { ++ val = 0; ++ } ++ mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, val); ++ ++ ret = genphy_c45_read_status(phydev); ++ if (ret < 0) ++ return ret; ++ ++ if (!phydev->link) { ++ phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN; ++ return 0; ++ } ++ ++ /* Read actual speed from vendor register. */ ++ val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL_VND2_PHYSR); ++ if (val < 0) ++ return val; ++ ++ rtlgen_decode_physr(phydev, val); ++ ++ return 0; ++} ++ ++static int rtl822xb_c45_read_status(struct phy_device *phydev) ++{ ++ int ret; ++ ++ ret = rtl822x_c45_read_status(phydev); ++ if (ret < 0) ++ return ret; ++ ++ rtl822xb_update_interface(phydev); ++ ++ return 0; ++} ++ ++static bool rtlgen_supports_2_5gbps(struct phy_device *phydev) ++{ ++ int val; ++ ++ phy_write(phydev, RTL821x_PAGE_SELECT, 0xa61); ++ val = phy_read(phydev, 0x13); ++ phy_write(phydev, RTL821x_PAGE_SELECT, 0); ++ ++ return val >= 0 && val & MDIO_PMA_SPEED_2_5G; ++} ++ ++/* On internal PHY's MMD reads over C22 always return 0. ++ * Check a MMD register which is known to be non-zero. ++ */ ++static bool rtlgen_supports_mmd(struct phy_device *phydev) ++{ ++ int val; ++ ++ phy_lock_mdio_bus(phydev); ++ __phy_write(phydev, MII_MMD_CTRL, MDIO_MMD_PCS); ++ __phy_write(phydev, MII_MMD_DATA, MDIO_PCS_EEE_ABLE); ++ __phy_write(phydev, MII_MMD_CTRL, MDIO_MMD_PCS | MII_MMD_CTRL_NOINCR); ++ val = __phy_read(phydev, MII_MMD_DATA); ++ phy_unlock_mdio_bus(phydev); ++ ++ return val > 0; ++} ++ ++static int rtlgen_match_phy_device(struct phy_device *phydev) ++{ ++ return phydev->phy_id == RTL_GENERIC_PHYID && ++ !rtlgen_supports_2_5gbps(phydev); ++} ++ ++static int rtl8226_match_phy_device(struct phy_device *phydev) ++{ ++ return phydev->phy_id == RTL_GENERIC_PHYID && ++ rtlgen_supports_2_5gbps(phydev) && ++ rtlgen_supports_mmd(phydev); ++} ++ ++static int rtlgen_is_c45_match(struct phy_device *phydev, unsigned int id, ++ bool is_c45) ++{ ++ if (phydev->is_c45) ++ return is_c45 && (id == phydev->c45_ids.device_ids[1]); ++ else ++ return !is_c45 && (id == phydev->phy_id); ++} ++ ++static int rtl8221b_match_phy_device(struct phy_device *phydev) ++{ ++ return phydev->phy_id == RTL_8221B && rtlgen_supports_mmd(phydev); ++} ++ ++static int rtl8221b_vb_cg_c22_match_phy_device(struct phy_device *phydev) ++{ ++ return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, false); ++} ++ ++static int rtl8221b_vb_cg_c45_match_phy_device(struct phy_device *phydev) ++{ ++ return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, true); ++} ++ ++static int rtl8221b_vn_cg_c22_match_phy_device(struct phy_device *phydev) ++{ ++ return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, false); ++} ++ ++static int rtl8221b_vn_cg_c45_match_phy_device(struct phy_device *phydev) ++{ ++ return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, true); ++} ++ ++static int rtl_internal_nbaset_match_phy_device(struct phy_device *phydev) ++{ ++ if (phydev->is_c45) ++ return false; ++ ++ switch (phydev->phy_id) { ++ case RTL_GENERIC_PHYID: ++ case RTL_8221B: ++ case RTL_8251B: ++ case 0x001cc841: ++ break; ++ default: ++ return false; ++ } ++ ++ return rtlgen_supports_2_5gbps(phydev) && !rtlgen_supports_mmd(phydev); ++} ++ ++static int rtl8251b_c45_match_phy_device(struct phy_device *phydev) ++{ ++ return rtlgen_is_c45_match(phydev, RTL_8251B, true); ++} ++ ++static int rtlgen_resume(struct phy_device *phydev) ++{ ++ int ret = genphy_resume(phydev); ++ ++ /* Internal PHY's from RTL8168h up may not be instantly ready */ ++ msleep(20); ++ ++ return ret; ++} ++ ++static int rtlgen_c45_resume(struct phy_device *phydev) ++{ ++ int ret = genphy_c45_pma_resume(phydev); ++ ++ msleep(20); ++ ++ return ret; ++} ++ ++static int rtl9000a_config_init(struct phy_device *phydev) ++{ ++ phydev->autoneg = AUTONEG_DISABLE; ++ phydev->speed = SPEED_100; ++ phydev->duplex = DUPLEX_FULL; ++ ++ return 0; ++} ++ ++static int rtl9000a_config_aneg(struct phy_device *phydev) ++{ ++ int ret; ++ u16 ctl = 0; ++ ++ switch (phydev->master_slave_set) { ++ case MASTER_SLAVE_CFG_MASTER_FORCE: ++ ctl |= CTL1000_AS_MASTER; ++ break; ++ case MASTER_SLAVE_CFG_SLAVE_FORCE: ++ break; ++ case MASTER_SLAVE_CFG_UNKNOWN: ++ case MASTER_SLAVE_CFG_UNSUPPORTED: ++ return 0; ++ default: ++ phydev_warn(phydev, "Unsupported Master/Slave mode\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ ret = phy_modify_changed(phydev, MII_CTRL1000, CTL1000_AS_MASTER, ctl); ++ if (ret == 1) ++ ret = genphy_soft_reset(phydev); ++ ++ return ret; ++} ++ ++static int rtl9000a_read_status(struct phy_device *phydev) ++{ ++ int ret; ++ ++ phydev->master_slave_get = MASTER_SLAVE_CFG_UNKNOWN; ++ phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN; ++ ++ ret = genphy_update_link(phydev); ++ if (ret) ++ return ret; ++ ++ ret = phy_read(phydev, MII_CTRL1000); ++ if (ret < 0) ++ return ret; ++ if (ret & CTL1000_AS_MASTER) ++ phydev->master_slave_get = MASTER_SLAVE_CFG_MASTER_FORCE; ++ else ++ phydev->master_slave_get = MASTER_SLAVE_CFG_SLAVE_FORCE; ++ ++ ret = phy_read(phydev, MII_STAT1000); ++ if (ret < 0) ++ return ret; ++ if (ret & LPA_1000MSRES) ++ phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER; ++ else ++ phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE; ++ ++ return 0; ++} ++ ++static int rtl9000a_ack_interrupt(struct phy_device *phydev) ++{ ++ int err; ++ ++ err = phy_read(phydev, RTL8211F_INSR); ++ ++ return (err < 0) ? err : 0; ++} ++ ++static int rtl9000a_config_intr(struct phy_device *phydev) ++{ ++ u16 val; ++ int err; ++ ++ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { ++ err = rtl9000a_ack_interrupt(phydev); ++ if (err) ++ return err; ++ ++ val = (u16)~RTL9000A_GINMR_LINK_STATUS; ++ err = phy_write_paged(phydev, 0xa42, RTL9000A_GINMR, val); ++ } else { ++ val = ~0; ++ err = phy_write_paged(phydev, 0xa42, RTL9000A_GINMR, val); ++ if (err) ++ return err; ++ ++ err = rtl9000a_ack_interrupt(phydev); ++ } ++ ++ return phy_write_paged(phydev, 0xa42, RTL9000A_GINMR, val); ++} ++ ++static irqreturn_t rtl9000a_handle_interrupt(struct phy_device *phydev) ++{ ++ int irq_status; ++ ++ irq_status = phy_read(phydev, RTL8211F_INSR); ++ if (irq_status < 0) { ++ phy_error(phydev); ++ return IRQ_NONE; ++ } ++ ++ if (!(irq_status & RTL8211F_INER_LINK_STATUS)) ++ return IRQ_NONE; ++ ++ phy_trigger_machine(phydev); ++ ++ return IRQ_HANDLED; ++} ++ ++static struct phy_driver realtek_drvs[] = { ++ { ++ PHY_ID_MATCH_EXACT(0x00008201), ++ .name = "RTL8201CP Ethernet", ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ }, { ++ PHY_ID_MATCH_EXACT(0x001cc816), ++ .name = "RTL8201F Fast Ethernet", ++ .config_intr = &rtl8201_config_intr, ++ .handle_interrupt = rtl8201_handle_interrupt, ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ }, { ++ PHY_ID_MATCH_MODEL(0x001cc880), ++ .name = "RTL8208 Fast Ethernet", ++ .read_mmd = genphy_read_mmd_unsupported, ++ .write_mmd = genphy_write_mmd_unsupported, ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ }, { ++ PHY_ID_MATCH_EXACT(0x001cc910), ++ .name = "RTL8211 Gigabit Ethernet", ++ .config_aneg = rtl8211_config_aneg, ++ .read_mmd = &genphy_read_mmd_unsupported, ++ .write_mmd = &genphy_write_mmd_unsupported, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ }, { ++ PHY_ID_MATCH_EXACT(0x001cc912), ++ .name = "RTL8211B Gigabit Ethernet", ++ .config_intr = &rtl8211b_config_intr, ++ .handle_interrupt = rtl821x_handle_interrupt, ++ .read_mmd = &genphy_read_mmd_unsupported, ++ .write_mmd = &genphy_write_mmd_unsupported, ++ .suspend = rtl8211b_suspend, ++ .resume = rtl8211b_resume, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ }, { ++ PHY_ID_MATCH_EXACT(0x001cc913), ++ .name = "RTL8211C Gigabit Ethernet", ++ .config_init = rtl8211c_config_init, ++ .read_mmd = &genphy_read_mmd_unsupported, ++ .write_mmd = &genphy_write_mmd_unsupported, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ }, { ++ PHY_ID_MATCH_EXACT(0x001cc914), ++ .name = "RTL8211DN Gigabit Ethernet", ++ .config_intr = rtl8211e_config_intr, ++ .handle_interrupt = rtl821x_handle_interrupt, ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ }, { ++ PHY_ID_MATCH_EXACT(0x001cc915), ++ .name = "RTL8211E Gigabit Ethernet", ++ .config_init = &rtl8211e_config_init, ++ .config_intr = &rtl8211e_config_intr, ++ .handle_interrupt = rtl821x_handle_interrupt, ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ }, { ++ PHY_ID_MATCH_EXACT(0x001cc916), ++ .name = "RTL8211F Gigabit Ethernet", ++ .probe = rtl821x_probe, ++ .config_init = &rtl8211f_config_init, ++ .read_status = rtlgen_read_status, ++ .config_intr = &rtl8211f_config_intr, ++ .handle_interrupt = rtl8211f_handle_interrupt, ++ .suspend = rtl821x_suspend, ++ .resume = rtl821x_resume, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ .flags = PHY_ALWAYS_CALL_SUSPEND, ++ .led_hw_is_supported = rtl8211f_led_hw_is_supported, ++ .led_hw_control_get = rtl8211f_led_hw_control_get, ++ .led_hw_control_set = rtl8211f_led_hw_control_set, ++ }, { ++ PHY_ID_MATCH_EXACT(RTL_8211FVD_PHYID), ++ .name = "RTL8211F-VD Gigabit Ethernet", ++ .probe = rtl821x_probe, ++ .config_init = &rtl8211f_config_init, ++ .read_status = rtlgen_read_status, ++ .config_intr = &rtl8211f_config_intr, ++ .handle_interrupt = rtl8211f_handle_interrupt, ++ .suspend = rtl821x_suspend, ++ .resume = rtl821x_resume, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ .flags = PHY_ALWAYS_CALL_SUSPEND, ++ }, { ++ .name = "Generic FE-GE Realtek PHY", ++ .match_phy_device = rtlgen_match_phy_device, ++ .read_status = rtlgen_read_status, ++ .suspend = genphy_suspend, ++ .resume = rtlgen_resume, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ .read_mmd = rtlgen_read_mmd, ++ .write_mmd = rtlgen_write_mmd, ++ }, { ++ .name = "RTL8226 2.5Gbps PHY", ++ .match_phy_device = rtl8226_match_phy_device, ++ .get_features = rtl822x_get_features, ++ .config_aneg = rtl822x_config_aneg, ++ .read_status = rtl822x_read_status, ++ .suspend = genphy_suspend, ++ .resume = rtlgen_resume, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ }, { ++ .match_phy_device = rtl8221b_match_phy_device, ++ .name = "RTL8226B_RTL8221B 2.5Gbps PHY", ++ .get_features = rtl822x_get_features, ++ .config_aneg = rtl822x_config_aneg, ++ .config_init = rtl822xb_config_init, ++ .get_rate_matching = rtl822xb_get_rate_matching, ++ .read_status = rtl822xb_read_status, ++ .suspend = genphy_suspend, ++ .resume = rtlgen_resume, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ }, { ++ PHY_ID_MATCH_EXACT(0x001cc838), ++ .name = "RTL8226-CG 2.5Gbps PHY", ++ .get_features = rtl822x_get_features, ++ .config_aneg = rtl822x_config_aneg, ++ .read_status = rtl822x_read_status, ++ .suspend = genphy_suspend, ++ .resume = rtlgen_resume, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ }, { ++ PHY_ID_MATCH_EXACT(0x001cc848), ++ .name = "RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY", ++ .get_features = rtl822x_get_features, ++ .config_aneg = rtl822x_config_aneg, ++ .config_init = rtl822xb_config_init, ++ .get_rate_matching = rtl822xb_get_rate_matching, ++ .read_status = rtl822xb_read_status, ++ .suspend = genphy_suspend, ++ .resume = rtlgen_resume, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ }, { ++ .match_phy_device = rtl8221b_vb_cg_c22_match_phy_device, ++ .name = "RTL8221B-VB-CG 2.5Gbps PHY (C22)", ++ .get_features = rtl822x_get_features, ++ .config_aneg = rtl822x_config_aneg, ++ .config_init = rtl822xb_config_init, ++ .get_rate_matching = rtl822xb_get_rate_matching, ++ .read_status = rtl822xb_read_status, ++ .suspend = genphy_suspend, ++ .resume = rtlgen_resume, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ }, { ++ .match_phy_device = rtl8221b_vb_cg_c45_match_phy_device, ++ .name = "RTL8221B-VB-CG 2.5Gbps PHY (C45)", ++ .config_init = rtl822xb_config_init, ++ .get_rate_matching = rtl822xb_get_rate_matching, ++ .get_features = rtl822x_c45_get_features, ++ .config_aneg = rtl822x_c45_config_aneg, ++ .read_status = rtl822xb_c45_read_status, ++ .suspend = genphy_c45_pma_suspend, ++ .resume = rtlgen_c45_resume, ++ }, { ++ .match_phy_device = rtl8221b_vn_cg_c22_match_phy_device, ++ .name = "RTL8221B-VM-CG 2.5Gbps PHY (C22)", ++ .get_features = rtl822x_get_features, ++ .config_aneg = rtl822x_config_aneg, ++ .config_init = rtl822xb_config_init, ++ .get_rate_matching = rtl822xb_get_rate_matching, ++ .read_status = rtl822xb_read_status, ++ .suspend = genphy_suspend, ++ .resume = rtlgen_resume, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ }, { ++ .match_phy_device = rtl8221b_vn_cg_c45_match_phy_device, ++ .name = "RTL8221B-VN-CG 2.5Gbps PHY (C45)", ++ .config_init = rtl822xb_config_init, ++ .get_rate_matching = rtl822xb_get_rate_matching, ++ .get_features = rtl822x_c45_get_features, ++ .config_aneg = rtl822x_c45_config_aneg, ++ .read_status = rtl822xb_c45_read_status, ++ .suspend = genphy_c45_pma_suspend, ++ .resume = rtlgen_c45_resume, ++ }, { ++ .match_phy_device = rtl8251b_c45_match_phy_device, ++ .name = "RTL8251B 5Gbps PHY", ++ .get_features = rtl822x_get_features, ++ .config_aneg = rtl822x_config_aneg, ++ .read_status = rtl822x_read_status, ++ .suspend = genphy_suspend, ++ .resume = rtlgen_resume, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ }, { ++ .match_phy_device = rtl_internal_nbaset_match_phy_device, ++ .name = "Realtek Internal NBASE-T PHY", ++ .flags = PHY_IS_INTERNAL, ++ .get_features = rtl822x_get_features, ++ .config_aneg = rtl822x_config_aneg, ++ .read_status = rtl822x_read_status, ++ .suspend = genphy_suspend, ++ .resume = rtlgen_resume, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ .read_mmd = rtl822x_read_mmd, ++ .write_mmd = rtl822x_write_mmd, ++ }, { ++ PHY_ID_MATCH_EXACT(0x001ccad0), ++ .name = "RTL8224 2.5Gbps PHY", ++ .get_features = rtl822x_c45_get_features, ++ .config_aneg = rtl822x_c45_config_aneg, ++ .read_status = rtl822x_c45_read_status, ++ .suspend = genphy_c45_pma_suspend, ++ .resume = rtlgen_c45_resume, ++ }, { ++ PHY_ID_MATCH_EXACT(0x001cc961), ++ .name = "RTL8366RB Gigabit Ethernet", ++ .config_init = &rtl8366rb_config_init, ++ /* These interrupts are handled by the irq controller ++ * embedded inside the RTL8366RB, they get unmasked when the ++ * irq is requested and ACKed by reading the status register, ++ * which is done by the irqchip code. ++ */ ++ .config_intr = genphy_no_config_intr, ++ .handle_interrupt = genphy_handle_interrupt_no_ack, ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, ++ }, { ++ PHY_ID_MATCH_EXACT(0x001ccb00), ++ .name = "RTL9000AA_RTL9000AN Ethernet", ++ .features = PHY_BASIC_T1_FEATURES, ++ .config_init = rtl9000a_config_init, ++ .config_aneg = rtl9000a_config_aneg, ++ .read_status = rtl9000a_read_status, ++ .config_intr = rtl9000a_config_intr, ++ .handle_interrupt = rtl9000a_handle_interrupt, ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, ++ .read_page = rtl821x_read_page, ++ .write_page = rtl821x_write_page, ++ }, { ++ PHY_ID_MATCH_EXACT(0x001cc942), ++ .name = "RTL8365MB-VC Gigabit Ethernet", ++ /* Interrupt handling analogous to RTL8366RB */ ++ .config_intr = genphy_no_config_intr, ++ .handle_interrupt = genphy_handle_interrupt_no_ack, ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, ++ }, { ++ PHY_ID_MATCH_EXACT(0x001cc960), ++ .name = "RTL8366S Gigabit Ethernet", ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, ++ .read_mmd = genphy_read_mmd_unsupported, ++ .write_mmd = genphy_write_mmd_unsupported, ++ }, ++}; ++ ++module_phy_driver(realtek_drvs); ++ ++static const struct mdio_device_id __maybe_unused realtek_tbl[] = { ++ { PHY_ID_MATCH_VENDOR(0x001cc800) }, ++ { } ++}; ++ ++MODULE_DEVICE_TABLE(mdio, realtek_tbl); diff --git a/target/linux/generic/backport-6.12/781-11-v6.14-net-phy-realtek-add-hwmon-support-for-temp-sensor-on.patch b/target/linux/generic/backport-6.12/781-11-v6.14-net-phy-realtek-add-hwmon-support-for-temp-sensor-on.patch new file mode 100644 index 0000000000..2dec701028 --- /dev/null +++ b/target/linux/generic/backport-6.12/781-11-v6.14-net-phy-realtek-add-hwmon-support-for-temp-sensor-on.patch @@ -0,0 +1,173 @@ +From 33700ca45b7d2e1655d4cad95e25671e8a94e2f0 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Sat, 11 Jan 2025 21:51:24 +0100 +Subject: [PATCH] net: phy: realtek: add hwmon support for temp sensor on + RTL822x + +This adds hwmon support for the temperature sensor on RTL822x. +It's available on the standalone versions of the PHY's, and on +the integrated PHY's in RTL8125B/RTL8125D/RTL8126. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/ad6bfe9f-6375-4a00-84b4-bfb38a21bd71@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/realtek/Kconfig | 6 ++ + drivers/net/phy/realtek/Makefile | 1 + + drivers/net/phy/realtek/realtek.h | 10 ++++ + drivers/net/phy/realtek/realtek_hwmon.c | 79 +++++++++++++++++++++++++ + drivers/net/phy/realtek/realtek_main.c | 12 ++++ + 5 files changed, 108 insertions(+) + create mode 100644 drivers/net/phy/realtek/realtek.h + create mode 100644 drivers/net/phy/realtek/realtek_hwmon.c + +--- a/drivers/net/phy/realtek/Kconfig ++++ b/drivers/net/phy/realtek/Kconfig +@@ -3,3 +3,9 @@ config REALTEK_PHY + tristate "Realtek PHYs" + help + Currently supports RTL821x/RTL822x and fast ethernet PHYs ++ ++config REALTEK_PHY_HWMON ++ def_bool REALTEK_PHY && HWMON ++ depends on !(REALTEK_PHY=y && HWMON=m) ++ help ++ Optional hwmon support for the temperature sensor +--- a/drivers/net/phy/realtek/Makefile ++++ b/drivers/net/phy/realtek/Makefile +@@ -1,3 +1,4 @@ + # SPDX-License-Identifier: GPL-2.0 + realtek-y += realtek_main.o ++realtek-$(CONFIG_REALTEK_PHY_HWMON) += realtek_hwmon.o + obj-$(CONFIG_REALTEK_PHY) += realtek.o +--- /dev/null ++++ b/drivers/net/phy/realtek/realtek.h +@@ -0,0 +1,10 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++ ++#ifndef REALTEK_H ++#define REALTEK_H ++ ++#include ++ ++int rtl822x_hwmon_init(struct phy_device *phydev); ++ ++#endif /* REALTEK_H */ +--- /dev/null ++++ b/drivers/net/phy/realtek/realtek_hwmon.c +@@ -0,0 +1,79 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * HWMON support for Realtek PHY's ++ * ++ * Author: Heiner Kallweit ++ */ ++ ++#include ++#include ++ ++#include "realtek.h" ++ ++#define RTL822X_VND2_TSALRM 0xa662 ++#define RTL822X_VND2_TSRR 0xbd84 ++#define RTL822X_VND2_TSSR 0xb54c ++ ++static int rtl822x_hwmon_get_temp(int raw) ++{ ++ if (raw >= 512) ++ raw -= 1024; ++ ++ return 1000 * raw / 2; ++} ++ ++static int rtl822x_hwmon_read(struct device *dev, enum hwmon_sensor_types type, ++ u32 attr, int channel, long *val) ++{ ++ struct phy_device *phydev = dev_get_drvdata(dev); ++ int raw; ++ ++ switch (attr) { ++ case hwmon_temp_input: ++ raw = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_TSRR) & 0x3ff; ++ *val = rtl822x_hwmon_get_temp(raw); ++ break; ++ case hwmon_temp_max: ++ /* Chip reduces speed to 1G if threshold is exceeded */ ++ raw = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_TSSR) >> 6; ++ *val = rtl822x_hwmon_get_temp(raw); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static const struct hwmon_ops rtl822x_hwmon_ops = { ++ .visible = 0444, ++ .read = rtl822x_hwmon_read, ++}; ++ ++static const struct hwmon_channel_info * const rtl822x_hwmon_info[] = { ++ HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX), ++ NULL ++}; ++ ++static const struct hwmon_chip_info rtl822x_hwmon_chip_info = { ++ .ops = &rtl822x_hwmon_ops, ++ .info = rtl822x_hwmon_info, ++}; ++ ++int rtl822x_hwmon_init(struct phy_device *phydev) ++{ ++ struct device *hwdev, *dev = &phydev->mdio.dev; ++ const char *name; ++ ++ /* Ensure over-temp alarm is reset. */ ++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_TSALRM, 3); ++ ++ name = devm_hwmon_sanitize_name(dev, dev_name(dev)); ++ if (IS_ERR(name)) ++ return PTR_ERR(name); ++ ++ hwdev = devm_hwmon_device_register_with_info(dev, name, phydev, ++ &rtl822x_hwmon_chip_info, ++ NULL); ++ return PTR_ERR_OR_ZERO(hwdev); ++} +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -14,6 +14,8 @@ + #include + #include + ++#include "realtek.h" ++ + #define RTL821x_PHYSR 0x11 + #define RTL821x_PHYSR_DUPLEX BIT(13) + #define RTL821x_PHYSR_SPEED GENMASK(15, 14) +@@ -820,6 +822,15 @@ static int rtl822x_write_mmd(struct phy_ + return ret; + } + ++static int rtl822x_probe(struct phy_device *phydev) ++{ ++ if (IS_ENABLED(CONFIG_REALTEK_PHY_HWMON) && ++ phydev->phy_id != RTL_GENERIC_PHYID) ++ return rtl822x_hwmon_init(phydev); ++ ++ return 0; ++} ++ + static int rtl822xb_config_init(struct phy_device *phydev) + { + bool has_2500, has_sgmii; +@@ -1518,6 +1529,7 @@ static struct phy_driver realtek_drvs[] + .match_phy_device = rtl_internal_nbaset_match_phy_device, + .name = "Realtek Internal NBASE-T PHY", + .flags = PHY_IS_INTERNAL, ++ .probe = rtl822x_probe, + .get_features = rtl822x_get_features, + .config_aneg = rtl822x_config_aneg, + .read_status = rtl822x_read_status, diff --git a/target/linux/generic/backport-6.12/781-12-v6.14-net-phy-realtek-HWMON-support-for-standalone-version.patch b/target/linux/generic/backport-6.12/781-12-v6.14-net-phy-realtek-HWMON-support-for-standalone-version.patch new file mode 100644 index 0000000000..8b8c97c54f --- /dev/null +++ b/target/linux/generic/backport-6.12/781-12-v6.14-net-phy-realtek-HWMON-support-for-standalone-version.patch @@ -0,0 +1,64 @@ +From 64ff63aeefb03139ae27454bd4208244579ae88e Mon Sep 17 00:00:00 2001 +From: Aleksander Jan Bajkowski +Date: Fri, 17 Jan 2025 23:24:21 +0100 +Subject: [PATCH] net: phy: realtek: HWMON support for standalone versions of + RTL8221B and RTL8251 + +HWMON support has been added for the RTL8221/8251 PHYs integrated together +with the MAC inside the RTL8125/8126 chips. This patch extends temperature +reading support for standalone variants of the mentioned PHYs. + +I don't know whether the earlier revisions of the RTL8226 also have a +built-in temperature sensor, so they have been skipped for now. + +Tested on RTL8221B-VB-CG. + +Signed-off-by: Aleksander Jan Bajkowski +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + drivers/net/phy/realtek/realtek_main.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -1474,6 +1474,7 @@ static struct phy_driver realtek_drvs[] + }, { + .match_phy_device = rtl8221b_vb_cg_c22_match_phy_device, + .name = "RTL8221B-VB-CG 2.5Gbps PHY (C22)", ++ .probe = rtl822x_probe, + .get_features = rtl822x_get_features, + .config_aneg = rtl822x_config_aneg, + .config_init = rtl822xb_config_init, +@@ -1486,6 +1487,7 @@ static struct phy_driver realtek_drvs[] + }, { + .match_phy_device = rtl8221b_vb_cg_c45_match_phy_device, + .name = "RTL8221B-VB-CG 2.5Gbps PHY (C45)", ++ .probe = rtl822x_probe, + .config_init = rtl822xb_config_init, + .get_rate_matching = rtl822xb_get_rate_matching, + .get_features = rtl822x_c45_get_features, +@@ -1496,6 +1498,7 @@ static struct phy_driver realtek_drvs[] + }, { + .match_phy_device = rtl8221b_vn_cg_c22_match_phy_device, + .name = "RTL8221B-VM-CG 2.5Gbps PHY (C22)", ++ .probe = rtl822x_probe, + .get_features = rtl822x_get_features, + .config_aneg = rtl822x_config_aneg, + .config_init = rtl822xb_config_init, +@@ -1508,6 +1511,7 @@ static struct phy_driver realtek_drvs[] + }, { + .match_phy_device = rtl8221b_vn_cg_c45_match_phy_device, + .name = "RTL8221B-VN-CG 2.5Gbps PHY (C45)", ++ .probe = rtl822x_probe, + .config_init = rtl822xb_config_init, + .get_rate_matching = rtl822xb_get_rate_matching, + .get_features = rtl822x_c45_get_features, +@@ -1518,6 +1522,7 @@ static struct phy_driver realtek_drvs[] + }, { + .match_phy_device = rtl8251b_c45_match_phy_device, + .name = "RTL8251B 5Gbps PHY", ++ .probe = rtl822x_probe, + .get_features = rtl822x_get_features, + .config_aneg = rtl822x_config_aneg, + .read_status = rtl822x_read_status, diff --git a/target/linux/generic/backport-6.12/781-13-v6.15-net-phy-realtek-make-HWMON-support-a-user-visible-Kc.patch b/target/linux/generic/backport-6.12/781-13-v6.15-net-phy-realtek-make-HWMON-support-a-user-visible-Kc.patch new file mode 100644 index 0000000000..821d7ee879 --- /dev/null +++ b/target/linux/generic/backport-6.12/781-13-v6.15-net-phy-realtek-make-HWMON-support-a-user-visible-Kc.patch @@ -0,0 +1,35 @@ +From 51773846fab24a353bed4ebb660997ced4bc32d7 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Mon, 3 Feb 2025 21:33:39 +0100 +Subject: [PATCH] net: phy: realtek: make HWMON support a user-visible Kconfig + symbol + +Make config symbol REALTEK_PHY_HWMON user-visible, so that users can +remove support if not needed. + +Suggested-by: Geert Uytterhoeven +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/3466ee92-166a-4b0f-9ae7-42b9e046f333@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/realtek/Kconfig | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +--- a/drivers/net/phy/realtek/Kconfig ++++ b/drivers/net/phy/realtek/Kconfig +@@ -4,8 +4,12 @@ config REALTEK_PHY + help + Currently supports RTL821x/RTL822x and fast ethernet PHYs + ++if REALTEK_PHY ++ + config REALTEK_PHY_HWMON +- def_bool REALTEK_PHY && HWMON +- depends on !(REALTEK_PHY=y && HWMON=m) ++ bool "HWMON support for Realtek PHYs" ++ depends on HWMON && !(REALTEK_PHY=y && HWMON=m) + help + Optional hwmon support for the temperature sensor ++ ++endif # REALTEK_PHY diff --git a/target/linux/generic/backport-6.12/781-14-v6.15-net-phy-realtek-use-string-choices-helpers.patch b/target/linux/generic/backport-6.12/781-14-v6.15-net-phy-realtek-use-string-choices-helpers.patch new file mode 100644 index 0000000000..d3e09bc7cd --- /dev/null +++ b/target/linux/generic/backport-6.12/781-14-v6.15-net-phy-realtek-use-string-choices-helpers.patch @@ -0,0 +1,54 @@ +From 0bea93fdbaf8675b7e8124bdcaf51497dcc8bcfa Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Mon, 3 Feb 2025 21:41:36 +0100 +Subject: [PATCH] net: phy: realtek: use string choices helpers + +Use string choices helpers to simplify the code. + +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202501190707.qQS8PGHW-lkp@intel.com/ +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Signed-off-by: David S. Miller +--- + drivers/net/phy/realtek/realtek_main.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + + #include "realtek.h" + +@@ -422,11 +423,11 @@ static int rtl8211f_config_init(struct p + } else if (ret) { + dev_dbg(dev, + "%s 2ns TX delay (and changing the value from pin-strapping RXD1 or the bootloader)\n", +- val_txdly ? "Enabling" : "Disabling"); ++ str_enable_disable(val_txdly)); + } else { + dev_dbg(dev, + "2ns TX delay was already %s (by pin-strapping RXD1 or bootloader configuration)\n", +- val_txdly ? "enabled" : "disabled"); ++ str_enabled_disabled(val_txdly)); + } + + ret = phy_modify_paged_changed(phydev, 0xd08, 0x15, RTL8211F_RX_DELAY, +@@ -437,11 +438,11 @@ static int rtl8211f_config_init(struct p + } else if (ret) { + dev_dbg(dev, + "%s 2ns RX delay (and changing the value from pin-strapping RXD0 or the bootloader)\n", +- val_rxdly ? "Enabling" : "Disabling"); ++ str_enable_disable(val_rxdly)); + } else { + dev_dbg(dev, + "2ns RX delay was already %s (by pin-strapping RXD0 or bootloader configuration)\n", +- val_rxdly ? "enabled" : "disabled"); ++ str_enabled_disabled(val_rxdly)); + } + + if (priv->has_phycr2) { diff --git a/target/linux/generic/backport-6.12/781-15-v6.13-net-phy-realtek-read-duplex-and-gbit-master-from-PHY.patch b/target/linux/generic/backport-6.12/781-15-v6.13-net-phy-realtek-read-duplex-and-gbit-master-from-PHY.patch deleted file mode 100644 index e15218b169..0000000000 --- a/target/linux/generic/backport-6.12/781-15-v6.13-net-phy-realtek-read-duplex-and-gbit-master-from-PHY.patch +++ /dev/null @@ -1,106 +0,0 @@ -From 081c9c0265c91b8333165aa6230c20bcbc6f7cbf Mon Sep 17 00:00:00 2001 -From: Daniel Golle -Date: Thu, 10 Oct 2024 14:07:16 +0100 -Subject: [PATCH 3/5] net: phy: realtek: read duplex and gbit master from PHYSR - register - -The PHYSR MMD register is present and defined equally for all RTL82xx -Ethernet PHYs. -Read duplex and Gbit master bits from rtlgen_decode_speed() and rename -it to rtlgen_decode_physr(). - -Signed-off-by: Daniel Golle -Link: https://patch.msgid.link/b9a76341da851a18c985bc4774fa295babec79bb.1728565530.git.daniel@makrotopia.org -Signed-off-by: Paolo Abeni ---- - drivers/net/phy/realtek.c | 41 +++++++++++++++++++++++++++++++-------- - 1 file changed, 33 insertions(+), 8 deletions(-) - ---- a/drivers/net/phy/realtek.c -+++ b/drivers/net/phy/realtek.c -@@ -80,15 +80,18 @@ - - #define RTL822X_VND2_GANLPAR 0xa414 - --#define RTL822X_VND2_PHYSR 0xa434 -- - #define RTL8366RB_POWER_SAVE 0x15 - #define RTL8366RB_POWER_SAVE_ON BIT(12) - - #define RTL9000A_GINMR 0x14 - #define RTL9000A_GINMR_LINK_STATUS BIT(4) - --#define RTLGEN_SPEED_MASK 0x0630 -+#define RTL_VND2_PHYSR 0xa434 -+#define RTL_VND2_PHYSR_DUPLEX BIT(3) -+#define RTL_VND2_PHYSR_SPEEDL GENMASK(5, 4) -+#define RTL_VND2_PHYSR_SPEEDH GENMASK(10, 9) -+#define RTL_VND2_PHYSR_MASTER BIT(11) -+#define RTL_VND2_PHYSR_SPEED_MASK (RTL_VND2_PHYSR_SPEEDL | RTL_VND2_PHYSR_SPEEDH) - - #define RTL_GENERIC_PHYID 0x001cc800 - #define RTL_8211FVD_PHYID 0x001cc878 -@@ -660,9 +663,18 @@ static int rtl8366rb_config_init(struct - } - - /* get actual speed to cover the downshift case */ --static void rtlgen_decode_speed(struct phy_device *phydev, int val) -+static void rtlgen_decode_physr(struct phy_device *phydev, int val) - { -- switch (val & RTLGEN_SPEED_MASK) { -+ /* bit 3 -+ * 0: Half Duplex -+ * 1: Full Duplex -+ */ -+ if (val & RTL_VND2_PHYSR_DUPLEX) -+ phydev->duplex = DUPLEX_FULL; -+ else -+ phydev->duplex = DUPLEX_HALF; -+ -+ switch (val & RTL_VND2_PHYSR_SPEED_MASK) { - case 0x0000: - phydev->speed = SPEED_10; - break; -@@ -684,6 +696,19 @@ static void rtlgen_decode_speed(struct p - default: - break; - } -+ -+ /* bit 11 -+ * 0: Slave Mode -+ * 1: Master Mode -+ */ -+ if (phydev->speed >= 1000) { -+ if (val & RTL_VND2_PHYSR_MASTER) -+ phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER; -+ else -+ phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE; -+ } else { -+ phydev->master_slave_state = MASTER_SLAVE_STATE_UNSUPPORTED; -+ } - } - - static int rtlgen_read_status(struct phy_device *phydev) -@@ -701,7 +726,7 @@ static int rtlgen_read_status(struct phy - if (val < 0) - return val; - -- rtlgen_decode_speed(phydev, val); -+ rtlgen_decode_physr(phydev, val); - - return 0; - } -@@ -1007,11 +1032,11 @@ static int rtl822x_c45_read_status(struc - return 0; - - /* Read actual speed from vendor register. */ -- val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_PHYSR); -+ val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL_VND2_PHYSR); - if (val < 0) - return val; - -- rtlgen_decode_speed(phydev, val); -+ rtlgen_decode_physr(phydev, val); - - return 0; - } diff --git a/target/linux/generic/backport-6.12/781-15-v6.15-net-phy-realtek-improve-mmd-register-access-for-inte.patch b/target/linux/generic/backport-6.12/781-15-v6.15-net-phy-realtek-improve-mmd-register-access-for-inte.patch new file mode 100644 index 0000000000..3a3a20d58b --- /dev/null +++ b/target/linux/generic/backport-6.12/781-15-v6.15-net-phy-realtek-improve-mmd-register-access-for-inte.patch @@ -0,0 +1,134 @@ +From da681ed73fb980286fc29de707b35d76bb33e123 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Thu, 13 Feb 2025 20:18:17 +0100 +Subject: [PATCH] net: phy: realtek: improve mmd register access for internal + PHY's + +r8169 provides the MDIO bus for the internal PHY's. It has been extended +with c45 access functions for addressing MDIO_MMD_VEND2 registers. +So we can switch from paged access to directly addressing the +MDIO_MMD_VEND2 registers. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/a5f2333c-dda9-48ad-9801-77049766e632@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/realtek/realtek_main.c | 79 +++++++++++--------------- + 1 file changed, 33 insertions(+), 46 deletions(-) + +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -735,29 +735,31 @@ static int rtlgen_read_status(struct phy + return 0; + } + ++static int rtlgen_read_vend2(struct phy_device *phydev, int regnum) ++{ ++ return __mdiobus_c45_read(phydev->mdio.bus, 0, MDIO_MMD_VEND2, regnum); ++} ++ ++static int rtlgen_write_vend2(struct phy_device *phydev, int regnum, u16 val) ++{ ++ return __mdiobus_c45_write(phydev->mdio.bus, 0, MDIO_MMD_VEND2, regnum, ++ val); ++} ++ + static int rtlgen_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) + { + int ret; + +- if (devnum == MDIO_MMD_VEND2) { +- rtl821x_write_page(phydev, regnum >> 4); +- ret = __phy_read(phydev, 0x10 + ((regnum & 0xf) >> 1)); +- rtl821x_write_page(phydev, 0); +- } else if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) { +- rtl821x_write_page(phydev, 0xa5c); +- ret = __phy_read(phydev, 0x12); +- rtl821x_write_page(phydev, 0); +- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) { +- rtl821x_write_page(phydev, 0xa5d); +- ret = __phy_read(phydev, 0x10); +- rtl821x_write_page(phydev, 0); +- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE) { +- rtl821x_write_page(phydev, 0xa5d); +- ret = __phy_read(phydev, 0x11); +- rtl821x_write_page(phydev, 0); +- } else { ++ if (devnum == MDIO_MMD_VEND2) ++ ret = rtlgen_read_vend2(phydev, regnum); ++ else if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) ++ ret = rtlgen_read_vend2(phydev, 0xa5c4); ++ else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) ++ ret = rtlgen_read_vend2(phydev, 0xa5d0); ++ else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE) ++ ret = rtlgen_read_vend2(phydev, 0xa5d2); ++ else + ret = -EOPNOTSUPP; +- } + + return ret; + } +@@ -767,17 +769,12 @@ static int rtlgen_write_mmd(struct phy_d + { + int ret; + +- if (devnum == MDIO_MMD_VEND2) { +- rtl821x_write_page(phydev, regnum >> 4); +- ret = __phy_write(phydev, 0x10 + ((regnum & 0xf) >> 1), val); +- rtl821x_write_page(phydev, 0); +- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) { +- rtl821x_write_page(phydev, 0xa5d); +- ret = __phy_write(phydev, 0x10, val); +- rtl821x_write_page(phydev, 0); +- } else { ++ if (devnum == MDIO_MMD_VEND2) ++ ret = rtlgen_write_vend2(phydev, regnum, val); ++ else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) ++ ret = rtlgen_write_vend2(phydev, regnum, 0xa5d0); ++ else + ret = -EOPNOTSUPP; +- } + + return ret; + } +@@ -789,19 +786,12 @@ static int rtl822x_read_mmd(struct phy_d + if (ret != -EOPNOTSUPP) + return ret; + +- if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE2) { +- rtl821x_write_page(phydev, 0xa6e); +- ret = __phy_read(phydev, 0x16); +- rtl821x_write_page(phydev, 0); +- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) { +- rtl821x_write_page(phydev, 0xa6d); +- ret = __phy_read(phydev, 0x12); +- rtl821x_write_page(phydev, 0); +- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE2) { +- rtl821x_write_page(phydev, 0xa6d); +- ret = __phy_read(phydev, 0x10); +- rtl821x_write_page(phydev, 0); +- } ++ if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE2) ++ ret = rtlgen_read_vend2(phydev, 0xa6ec); ++ else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) ++ ret = rtlgen_read_vend2(phydev, 0xa6d4); ++ else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE2) ++ ret = rtlgen_read_vend2(phydev, 0xa6d0); + + return ret; + } +@@ -814,11 +804,8 @@ static int rtl822x_write_mmd(struct phy_ + if (ret != -EOPNOTSUPP) + return ret; + +- if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) { +- rtl821x_write_page(phydev, 0xa6d); +- ret = __phy_write(phydev, 0x12, val); +- rtl821x_write_page(phydev, 0); +- } ++ if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) ++ ret = rtlgen_write_vend2(phydev, 0xa6d4, val); + + return ret; + } diff --git a/target/linux/generic/backport-6.12/781-16-v6.13-net-phy-realtek-change-order-of-calls-in-C22-read_st.patch b/target/linux/generic/backport-6.12/781-16-v6.13-net-phy-realtek-change-order-of-calls-in-C22-read_st.patch deleted file mode 100644 index be7136b375..0000000000 --- a/target/linux/generic/backport-6.12/781-16-v6.13-net-phy-realtek-change-order-of-calls-in-C22-read_st.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 68d5cd09e8919679ce13b85950debea4b2e98e04 Mon Sep 17 00:00:00 2001 -From: Daniel Golle -Date: Thu, 10 Oct 2024 14:07:26 +0100 -Subject: [PATCH 4/5] net: phy: realtek: change order of calls in C22 - read_status() - -Always call rtlgen_read_status() first, so genphy_read_status() which -is called by it clears bits in case auto-negotiation has not completed. -Also clear 10GBT link-partner advertisement bits in case auto-negotiation -is disabled or has not completed. - -Suggested-by: Russell King (Oracle) -Signed-off-by: Daniel Golle -Link: https://patch.msgid.link/b15929a41621d215c6b2b57393368086589569ec.1728565530.git.daniel@makrotopia.org -Signed-off-by: Paolo Abeni ---- - drivers/net/phy/realtek.c | 22 +++++++++++++++------- - 1 file changed, 15 insertions(+), 7 deletions(-) - ---- a/drivers/net/phy/realtek.c -+++ b/drivers/net/phy/realtek.c -@@ -949,17 +949,25 @@ static void rtl822xb_update_interface(st - - static int rtl822x_read_status(struct phy_device *phydev) - { -- if (phydev->autoneg == AUTONEG_ENABLE) { -- int lpadv = phy_read_paged(phydev, 0xa5d, 0x13); -+ int lpadv, ret; - -- if (lpadv < 0) -- return lpadv; -+ ret = rtlgen_read_status(phydev); -+ if (ret < 0) -+ return ret; - -- mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, -- lpadv); -+ if (phydev->autoneg == AUTONEG_DISABLE || -+ !phydev->autoneg_complete) { -+ mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, 0); -+ return 0; - } - -- return rtlgen_read_status(phydev); -+ lpadv = phy_read_paged(phydev, 0xa5d, 0x13); -+ if (lpadv < 0) -+ return lpadv; -+ -+ mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, lpadv); -+ -+ return 0; - } - - static int rtl822xb_read_status(struct phy_device *phydev) diff --git a/target/linux/generic/backport-6.12/781-16-v6.15-net-phy-realtek-switch-from-paged-to-MMD-ops-in-rtl8.patch b/target/linux/generic/backport-6.12/781-16-v6.15-net-phy-realtek-switch-from-paged-to-MMD-ops-in-rtl8.patch new file mode 100644 index 0000000000..5e3c3ce70a --- /dev/null +++ b/target/linux/generic/backport-6.12/781-16-v6.15-net-phy-realtek-switch-from-paged-to-MMD-ops-in-rtl8.patch @@ -0,0 +1,52 @@ +From 02d3b306ac2f0b174753d1c5b9e4e5fb8ec5057e Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Thu, 13 Feb 2025 20:19:14 +0100 +Subject: [PATCH] net: phy: realtek: switch from paged to MMD ops in rtl822x + functions + +The MDIO bus provided by r8169 for the internal PHY's now supports +c45 ops for the MDIO_MMD_VEND2 device. So we can switch to standard +MMD ops here. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/81416f95-0fac-4225-87b4-828e3738b8ed@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/realtek/realtek_main.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -901,7 +901,7 @@ static int rtl822x_get_features(struct p + { + int val; + +- val = phy_read_paged(phydev, 0xa61, 0x13); ++ val = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xa616); + if (val < 0) + return val; + +@@ -922,10 +922,9 @@ static int rtl822x_config_aneg(struct ph + if (phydev->autoneg == AUTONEG_ENABLE) { + u16 adv = linkmode_adv_to_mii_10gbt_adv_t(phydev->advertising); + +- ret = phy_modify_paged_changed(phydev, 0xa5d, 0x12, +- MDIO_AN_10GBT_CTRL_ADV2_5G | +- MDIO_AN_10GBT_CTRL_ADV5G, +- adv); ++ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, 0xa5d4, ++ MDIO_AN_10GBT_CTRL_ADV2_5G | ++ MDIO_AN_10GBT_CTRL_ADV5G, adv); + if (ret < 0) + return ret; + } +@@ -969,7 +968,7 @@ static int rtl822x_read_status(struct ph + !phydev->autoneg_complete) + return 0; + +- lpadv = phy_read_paged(phydev, 0xa5d, 0x13); ++ lpadv = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xa5d6); + if (lpadv < 0) + return lpadv; + diff --git a/target/linux/generic/backport-6.12/781-17-v6.13-net-phy-realtek-clear-1000Base-T-link-partner-advert.patch b/target/linux/generic/backport-6.12/781-17-v6.13-net-phy-realtek-clear-1000Base-T-link-partner-advert.patch deleted file mode 100644 index 3847d5803a..0000000000 --- a/target/linux/generic/backport-6.12/781-17-v6.13-net-phy-realtek-clear-1000Base-T-link-partner-advert.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 5cb409b3960e75467cbb0a8e1e5596b4490570e3 Mon Sep 17 00:00:00 2001 -From: Daniel Golle -Date: Thu, 10 Oct 2024 14:07:39 +0100 -Subject: [PATCH 5/5] net: phy: realtek: clear 1000Base-T link partner - advertisement - -Clear 1000Base-T link partner advertisement bits in Clause-45 -read_status() function in case auto-negotiation is disabled or has not -been completed. - -Signed-off-by: Daniel Golle -Link: https://patch.msgid.link/9dc9b47b2d675708afef3ad366bfd78eb584d958.1728565530.git.daniel@makrotopia.org -Signed-off-by: Paolo Abeni ---- - drivers/net/phy/realtek.c | 4 ++++ - 1 file changed, 4 insertions(+) - ---- a/drivers/net/phy/realtek.c -+++ b/drivers/net/phy/realtek.c -@@ -1026,6 +1026,10 @@ static int rtl822x_c45_read_status(struc - if (ret < 0) - return ret; - -+ if (phydev->autoneg == AUTONEG_DISABLE || -+ !genphy_c45_aneg_done(phydev)) -+ mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, 0); -+ - /* Vendor register as C45 has no standardized support for 1000BaseT */ - if (phydev->autoneg == AUTONEG_ENABLE) { - val = phy_read_mmd(phydev, MDIO_MMD_VEND2, diff --git a/target/linux/generic/backport-6.12/781-17-v6.15-net-phy-realtek-add-helper-RTL822X_VND2_C22_REG.patch b/target/linux/generic/backport-6.12/781-17-v6.15-net-phy-realtek-add-helper-RTL822X_VND2_C22_REG.patch new file mode 100644 index 0000000000..5134d08b1c --- /dev/null +++ b/target/linux/generic/backport-6.12/781-17-v6.15-net-phy-realtek-add-helper-RTL822X_VND2_C22_REG.patch @@ -0,0 +1,48 @@ +From 8af2136e77989a64fae0284bf76fd584e32edd3a Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Fri, 14 Feb 2025 21:31:14 +0100 +Subject: [PATCH] net: phy: realtek: add helper RTL822X_VND2_C22_REG + +C22 register space is mapped to 0xa400 in MMD VEND2 register space. +Add a helper to access mapped C22 registers. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/6344277b-c5c7-449b-ac89-d5425306ca76@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/realtek/realtek_main.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -79,9 +79,7 @@ + /* RTL822X_VND2_XXXXX registers are only accessible when phydev->is_c45 + * is set, they cannot be accessed by C45-over-C22. + */ +-#define RTL822X_VND2_GBCR 0xa412 +- +-#define RTL822X_VND2_GANLPAR 0xa414 ++#define RTL822X_VND2_C22_REG(reg) (0xa400 + 2 * (reg)) + + #define RTL8366RB_POWER_SAVE 0x15 + #define RTL8366RB_POWER_SAVE_ON BIT(12) +@@ -1015,7 +1013,8 @@ static int rtl822x_c45_config_aneg(struc + val = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising); + + /* Vendor register as C45 has no standardized support for 1000BaseT */ +- ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, RTL822X_VND2_GBCR, ++ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, ++ RTL822X_VND2_C22_REG(MII_CTRL1000), + ADVERTISE_1000FULL, val); + if (ret < 0) + return ret; +@@ -1032,7 +1031,7 @@ static int rtl822x_c45_read_status(struc + /* Vendor register as C45 has no standardized support for 1000BaseT */ + if (phydev->autoneg == AUTONEG_ENABLE && genphy_c45_aneg_done(phydev)) { + val = phy_read_mmd(phydev, MDIO_MMD_VEND2, +- RTL822X_VND2_GANLPAR); ++ RTL822X_VND2_C22_REG(MII_STAT1000)); + if (val < 0) + return val; + } else { diff --git a/target/linux/generic/backport-6.12/781-18-v6.13-net-phy-realtek-merge-the-drivers-for-internal-NBase.patch b/target/linux/generic/backport-6.12/781-18-v6.13-net-phy-realtek-merge-the-drivers-for-internal-NBase.patch deleted file mode 100644 index 771f60df91..0000000000 --- a/target/linux/generic/backport-6.12/781-18-v6.13-net-phy-realtek-merge-the-drivers-for-internal-NBase.patch +++ /dev/null @@ -1,136 +0,0 @@ -From f87a17ed3b51fba4dfdd8f8b643b5423a85fc551 Mon Sep 17 00:00:00 2001 -From: Heiner Kallweit -Date: Tue, 15 Oct 2024 07:47:14 +0200 -Subject: [PATCH] net: phy: realtek: merge the drivers for internal NBase-T - PHY's - -The Realtek RTL8125/RTL8126 NBase-T MAC/PHY chips have internal PHY's -which are register-compatible, at least for the registers we use here. -So let's use just one PHY driver to support all of them. -These internal PHY's exist also as external C45 PHY's, but on the -internal PHY's no access to MMD registers is possible. This can be -used to differentiate between the internal and external version. - -As a side effect the drivers for two now external-only drivers don't -require read_mmd/write_mmd hooks any longer. - -Signed-off-by: Heiner Kallweit -Link: https://patch.msgid.link/c57081a6-811f-4571-ab35-34f4ca6de9af@gmail.com -Signed-off-by: Paolo Abeni ---- - drivers/net/phy/realtek.c | 53 +++++++++++++++++++++++++++++++-------- - 1 file changed, 43 insertions(+), 10 deletions(-) - ---- a/drivers/net/phy/realtek.c -+++ b/drivers/net/phy/realtek.c -@@ -95,6 +95,7 @@ - - #define RTL_GENERIC_PHYID 0x001cc800 - #define RTL_8211FVD_PHYID 0x001cc878 -+#define RTL_8221B 0x001cc840 - #define RTL_8221B_VB_CG 0x001cc849 - #define RTL_8221B_VN_CG 0x001cc84a - #define RTL_8251B 0x001cc862 -@@ -1077,6 +1078,23 @@ static bool rtlgen_supports_2_5gbps(stru - return val >= 0 && val & MDIO_PMA_SPEED_2_5G; - } - -+/* On internal PHY's MMD reads over C22 always return 0. -+ * Check a MMD register which is known to be non-zero. -+ */ -+static bool rtlgen_supports_mmd(struct phy_device *phydev) -+{ -+ int val; -+ -+ phy_lock_mdio_bus(phydev); -+ __phy_write(phydev, MII_MMD_CTRL, MDIO_MMD_PCS); -+ __phy_write(phydev, MII_MMD_DATA, MDIO_PCS_EEE_ABLE); -+ __phy_write(phydev, MII_MMD_CTRL, MDIO_MMD_PCS | MII_MMD_CTRL_NOINCR); -+ val = __phy_read(phydev, MII_MMD_DATA); -+ phy_unlock_mdio_bus(phydev); -+ -+ return val > 0; -+} -+ - static int rtlgen_match_phy_device(struct phy_device *phydev) - { - return phydev->phy_id == RTL_GENERIC_PHYID && -@@ -1086,7 +1104,8 @@ static int rtlgen_match_phy_device(struc - static int rtl8226_match_phy_device(struct phy_device *phydev) - { - return phydev->phy_id == RTL_GENERIC_PHYID && -- rtlgen_supports_2_5gbps(phydev); -+ rtlgen_supports_2_5gbps(phydev) && -+ rtlgen_supports_mmd(phydev); - } - - static int rtlgen_is_c45_match(struct phy_device *phydev, unsigned int id, -@@ -1098,6 +1117,11 @@ static int rtlgen_is_c45_match(struct ph - return !is_c45 && (id == phydev->phy_id); - } - -+static int rtl8221b_match_phy_device(struct phy_device *phydev) -+{ -+ return phydev->phy_id == RTL_8221B && rtlgen_supports_mmd(phydev); -+} -+ - static int rtl8221b_vb_cg_c22_match_phy_device(struct phy_device *phydev) - { - return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, false); -@@ -1118,9 +1142,21 @@ static int rtl8221b_vn_cg_c45_match_phy_ - return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, true); - } - --static int rtl8251b_c22_match_phy_device(struct phy_device *phydev) -+static int rtl_internal_nbaset_match_phy_device(struct phy_device *phydev) - { -- return rtlgen_is_c45_match(phydev, RTL_8251B, false); -+ if (phydev->is_c45) -+ return false; -+ -+ switch (phydev->phy_id) { -+ case RTL_GENERIC_PHYID: -+ case RTL_8221B: -+ case RTL_8251B: -+ break; -+ default: -+ return false; -+ } -+ -+ return rtlgen_supports_2_5gbps(phydev) && !rtlgen_supports_mmd(phydev); - } - - static int rtl8251b_c45_match_phy_device(struct phy_device *phydev) -@@ -1382,10 +1418,8 @@ static struct phy_driver realtek_drvs[] - .resume = rtlgen_resume, - .read_page = rtl821x_read_page, - .write_page = rtl821x_write_page, -- .read_mmd = rtl822x_read_mmd, -- .write_mmd = rtl822x_write_mmd, - }, { -- PHY_ID_MATCH_EXACT(0x001cc840), -+ .match_phy_device = rtl8221b_match_phy_device, - .name = "RTL8226B_RTL8221B 2.5Gbps PHY", - .get_features = rtl822x_get_features, - .config_aneg = rtl822x_config_aneg, -@@ -1396,8 +1430,6 @@ static struct phy_driver realtek_drvs[] - .resume = rtlgen_resume, - .read_page = rtl821x_read_page, - .write_page = rtl821x_write_page, -- .read_mmd = rtl822x_read_mmd, -- .write_mmd = rtl822x_write_mmd, - }, { - PHY_ID_MATCH_EXACT(0x001cc838), - .name = "RTL8226-CG 2.5Gbps PHY", -@@ -1475,8 +1507,9 @@ static struct phy_driver realtek_drvs[] - .read_page = rtl821x_read_page, - .write_page = rtl821x_write_page, - }, { -- .match_phy_device = rtl8251b_c22_match_phy_device, -- .name = "RTL8126A-internal 5Gbps PHY", -+ .match_phy_device = rtl_internal_nbaset_match_phy_device, -+ .name = "Realtek Internal NBASE-T PHY", -+ .flags = PHY_IS_INTERNAL, - .get_features = rtl822x_get_features, - .config_aneg = rtl822x_config_aneg, - .read_status = rtl822x_read_status, diff --git a/target/linux/generic/backport-6.12/781-18-v6.15-net-phy-realtek-add-defines-for-shadowed-c45-standar.patch b/target/linux/generic/backport-6.12/781-18-v6.15-net-phy-realtek-add-defines-for-shadowed-c45-standar.patch new file mode 100644 index 0000000000..ff7d5b1fb6 --- /dev/null +++ b/target/linux/generic/backport-6.12/781-18-v6.15-net-phy-realtek-add-defines-for-shadowed-c45-standar.patch @@ -0,0 +1,113 @@ +From fabcfd6d10999024a721ae1b965b57eb8a305ace Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Sat, 15 Feb 2025 14:29:15 +0100 +Subject: [PATCH] net: phy: realtek: add defines for shadowed c45 standard + registers + +Realtek shadows standard c45 registers in VEND2 device register space. +Add defines for these VEND2 registers, based on the names of the +standard c45 registers. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/c90bdf76-f8b8-4d06-9656-7a52d5658ee6@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/realtek/realtek_main.c | 33 +++++++++++++++++--------- + 1 file changed, 22 insertions(+), 11 deletions(-) + +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -94,6 +94,16 @@ + #define RTL_VND2_PHYSR_MASTER BIT(11) + #define RTL_VND2_PHYSR_SPEED_MASK (RTL_VND2_PHYSR_SPEEDL | RTL_VND2_PHYSR_SPEEDH) + ++#define RTL_MDIO_PCS_EEE_ABLE 0xa5c4 ++#define RTL_MDIO_AN_EEE_ADV 0xa5d0 ++#define RTL_MDIO_AN_EEE_LPABLE 0xa5d2 ++#define RTL_MDIO_AN_10GBT_CTRL 0xa5d4 ++#define RTL_MDIO_AN_10GBT_STAT 0xa5d6 ++#define RTL_MDIO_PMA_SPEED 0xa616 ++#define RTL_MDIO_AN_EEE_LPABLE2 0xa6d0 ++#define RTL_MDIO_AN_EEE_ADV2 0xa6d4 ++#define RTL_MDIO_PCS_EEE_ABLE2 0xa6ec ++ + #define RTL_GENERIC_PHYID 0x001cc800 + #define RTL_8211FVD_PHYID 0x001cc878 + #define RTL_8221B 0x001cc840 +@@ -751,11 +761,11 @@ static int rtlgen_read_mmd(struct phy_de + if (devnum == MDIO_MMD_VEND2) + ret = rtlgen_read_vend2(phydev, regnum); + else if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) +- ret = rtlgen_read_vend2(phydev, 0xa5c4); ++ ret = rtlgen_read_vend2(phydev, RTL_MDIO_PCS_EEE_ABLE); + else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) +- ret = rtlgen_read_vend2(phydev, 0xa5d0); ++ ret = rtlgen_read_vend2(phydev, RTL_MDIO_AN_EEE_ADV); + else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE) +- ret = rtlgen_read_vend2(phydev, 0xa5d2); ++ ret = rtlgen_read_vend2(phydev, RTL_MDIO_AN_EEE_LPABLE); + else + ret = -EOPNOTSUPP; + +@@ -770,7 +780,7 @@ static int rtlgen_write_mmd(struct phy_d + if (devnum == MDIO_MMD_VEND2) + ret = rtlgen_write_vend2(phydev, regnum, val); + else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) +- ret = rtlgen_write_vend2(phydev, regnum, 0xa5d0); ++ ret = rtlgen_write_vend2(phydev, regnum, RTL_MDIO_AN_EEE_ADV); + else + ret = -EOPNOTSUPP; + +@@ -785,11 +795,11 @@ static int rtl822x_read_mmd(struct phy_d + return ret; + + if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE2) +- ret = rtlgen_read_vend2(phydev, 0xa6ec); ++ ret = rtlgen_read_vend2(phydev, RTL_MDIO_PCS_EEE_ABLE2); + else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) +- ret = rtlgen_read_vend2(phydev, 0xa6d4); ++ ret = rtlgen_read_vend2(phydev, RTL_MDIO_AN_EEE_ADV2); + else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE2) +- ret = rtlgen_read_vend2(phydev, 0xa6d0); ++ ret = rtlgen_read_vend2(phydev, RTL_MDIO_AN_EEE_LPABLE2); + + return ret; + } +@@ -803,7 +813,7 @@ static int rtl822x_write_mmd(struct phy_ + return ret; + + if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) +- ret = rtlgen_write_vend2(phydev, 0xa6d4, val); ++ ret = rtlgen_write_vend2(phydev, RTL_MDIO_AN_EEE_ADV2, val); + + return ret; + } +@@ -899,7 +909,7 @@ static int rtl822x_get_features(struct p + { + int val; + +- val = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xa616); ++ val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL_MDIO_PMA_SPEED); + if (val < 0) + return val; + +@@ -920,7 +930,8 @@ static int rtl822x_config_aneg(struct ph + if (phydev->autoneg == AUTONEG_ENABLE) { + u16 adv = linkmode_adv_to_mii_10gbt_adv_t(phydev->advertising); + +- ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, 0xa5d4, ++ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, ++ RTL_MDIO_AN_10GBT_CTRL, + MDIO_AN_10GBT_CTRL_ADV2_5G | + MDIO_AN_10GBT_CTRL_ADV5G, adv); + if (ret < 0) +@@ -966,7 +977,7 @@ static int rtl822x_read_status(struct ph + !phydev->autoneg_complete) + return 0; + +- lpadv = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xa5d6); ++ lpadv = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL_MDIO_AN_10GBT_STAT); + if (lpadv < 0) + return lpadv; + diff --git a/target/linux/generic/backport-6.12/781-19-v6.13-net-phy-realtek-add-RTL8125D-internal-PHY.patch b/target/linux/generic/backport-6.12/781-19-v6.13-net-phy-realtek-add-RTL8125D-internal-PHY.patch deleted file mode 100644 index 4b9b9e8d48..0000000000 --- a/target/linux/generic/backport-6.12/781-19-v6.13-net-phy-realtek-add-RTL8125D-internal-PHY.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 8989bad541133c43550bff2b80edbe37b8fb9659 Mon Sep 17 00:00:00 2001 -From: Heiner Kallweit -Date: Thu, 17 Oct 2024 18:01:13 +0200 -Subject: [PATCH] net: phy: realtek: add RTL8125D-internal PHY - -The first boards show up with Realtek's RTL8125D. This MAC/PHY chip -comes with an integrated 2.5Gbps PHY with ID 0x001cc841. It's not -clear yet whether there's an external version of this PHY and how -Realtek calls it, therefore use the numeric id for now. - -Link: https://lore.kernel.org/netdev/2ada65e1-5dfa-456c-9334-2bc51272e9da@gmail.com/T/ -Signed-off-by: Heiner Kallweit -Message-ID: <7d2924de-053b-44d2-a479-870dc3878170@gmail.com> -Reviewed-by: Andrew Lunn -Signed-off-by: Andrew Lunn ---- - drivers/net/phy/realtek.c | 1 + - 1 file changed, 1 insertion(+) - ---- a/drivers/net/phy/realtek.c -+++ b/drivers/net/phy/realtek.c -@@ -1151,6 +1151,7 @@ static int rtl_internal_nbaset_match_phy - case RTL_GENERIC_PHYID: - case RTL_8221B: - case RTL_8251B: -+ case 0x001cc841: - break; - default: - return false; diff --git a/target/linux/generic/backport-6.12/781-19-v6.15-net-phy-realtek-disable-PHY-mode-EEE.patch b/target/linux/generic/backport-6.12/781-19-v6.15-net-phy-realtek-disable-PHY-mode-EEE.patch new file mode 100644 index 0000000000..4d755d4e22 --- /dev/null +++ b/target/linux/generic/backport-6.12/781-19-v6.15-net-phy-realtek-disable-PHY-mode-EEE.patch @@ -0,0 +1,54 @@ +From bfc17c1658353f22843c7c13e27c2d31950f1887 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Sun, 16 Mar 2025 12:39:54 +0000 +Subject: [PATCH] net: phy: realtek: disable PHY-mode EEE + +Realtek RTL8211F has a "PHY-mode" EEE support which interferes with an +IEEE 802.3 compliant implementation. This mode defaults to enabled, and +results in the MAC receive path not seeing the link transition to LPI +state. + +Fix this by disabling PHY-mode EEE. + +Signed-off-by: Russell King (Oracle) +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/E1ttnHW-00785s-Uq@rmk-PC.armlinux.org.uk +Signed-off-by: Paolo Abeni +--- + drivers/net/phy/realtek/realtek_main.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +--- a/drivers/net/phy/realtek/realtek_main.c ++++ b/drivers/net/phy/realtek/realtek_main.c +@@ -33,6 +33,9 @@ + + #define RTL8211F_PHYCR1 0x18 + #define RTL8211F_PHYCR2 0x19 ++#define RTL8211F_CLKOUT_EN BIT(0) ++#define RTL8211F_PHYCR2_PHY_EEE_ENABLE BIT(5) ++ + #define RTL8211F_INSR 0x1d + + #define RTL8211F_LEDCR 0x10 +@@ -55,8 +58,6 @@ + #define RTL8211E_TX_DELAY BIT(12) + #define RTL8211E_RX_DELAY BIT(11) + +-#define RTL8211F_CLKOUT_EN BIT(0) +- + #define RTL8201F_ISR 0x1e + #define RTL8201F_ISR_ANERR BIT(15) + #define RTL8201F_ISR_DUPLEX BIT(13) +@@ -453,6 +454,12 @@ static int rtl8211f_config_init(struct p + str_enabled_disabled(val_rxdly)); + } + ++ /* Disable PHY-mode EEE so LPI is passed to the MAC */ ++ ret = phy_modify_paged(phydev, 0xa43, RTL8211F_PHYCR2, ++ RTL8211F_PHYCR2_PHY_EEE_ENABLE, 0); ++ if (ret) ++ return ret; ++ + if (priv->has_phycr2) { + ret = phy_modify_paged(phydev, 0xa43, RTL8211F_PHYCR2, + RTL8211F_CLKOUT_EN, priv->phycr2); diff --git a/target/linux/generic/backport-6.12/781-20-v6.14-net-phy-realtek-clear-1000Base-T-lpa-if-link-is-down.patch b/target/linux/generic/backport-6.12/781-20-v6.14-net-phy-realtek-clear-1000Base-T-lpa-if-link-is-down.patch deleted file mode 100644 index 3e9631e4a3..0000000000 --- a/target/linux/generic/backport-6.12/781-20-v6.14-net-phy-realtek-clear-1000Base-T-lpa-if-link-is-down.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 34d5a86ff7bbe225fba3ad91f9b4dc85fb408e18 Mon Sep 17 00:00:00 2001 -From: Daniel Golle -Date: Wed, 15 Jan 2025 14:43:35 +0000 -Subject: [PATCH] net: phy: realtek: clear 1000Base-T lpa if link is down - -Only read 1000Base-T link partner advertisement if autonegotiation has -completed and otherwise 1000Base-T link partner advertisement bits. - -This fixes bogus 1000Base-T link partner advertisement after link goes -down (eg. by disconnecting the wire). -Fixes: 5cb409b3960e ("net: phy: realtek: clear 1000Base-T link partner advertisement") -Signed-off-by: Daniel Golle -Reviewed-by: Michal Swiatkowski -Signed-off-by: David S. Miller ---- - drivers/net/phy/realtek.c | 19 ++++++++----------- - 1 file changed, 8 insertions(+), 11 deletions(-) - ---- a/drivers/net/phy/realtek.c -+++ b/drivers/net/phy/realtek.c -@@ -1023,23 +1023,20 @@ static int rtl822x_c45_read_status(struc - { - int ret, val; - -- ret = genphy_c45_read_status(phydev); -- if (ret < 0) -- return ret; -- -- if (phydev->autoneg == AUTONEG_DISABLE || -- !genphy_c45_aneg_done(phydev)) -- mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, 0); -- - /* Vendor register as C45 has no standardized support for 1000BaseT */ -- if (phydev->autoneg == AUTONEG_ENABLE) { -+ if (phydev->autoneg == AUTONEG_ENABLE && genphy_c45_aneg_done(phydev)) { - val = phy_read_mmd(phydev, MDIO_MMD_VEND2, - RTL822X_VND2_GANLPAR); - if (val < 0) - return val; -- -- mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, val); -+ } else { -+ val = 0; - } -+ mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, val); -+ -+ ret = genphy_c45_read_status(phydev); -+ if (ret < 0) -+ return ret; - - if (!phydev->link) - return 0; diff --git a/target/linux/generic/backport-6.12/781-21-v6.14-net-phy-realtek-clear-master_slave_state-if-link-is-.patch b/target/linux/generic/backport-6.12/781-21-v6.14-net-phy-realtek-clear-master_slave_state-if-link-is-.patch deleted file mode 100644 index 778602d3e5..0000000000 --- a/target/linux/generic/backport-6.12/781-21-v6.14-net-phy-realtek-clear-master_slave_state-if-link-is-.patch +++ /dev/null @@ -1,35 +0,0 @@ -From ea8318cb33e593bbfc59d637eae45a69732c5387 Mon Sep 17 00:00:00 2001 -From: Daniel Golle -Date: Wed, 15 Jan 2025 14:43:43 +0000 -Subject: [PATCH] net: phy: realtek: clear master_slave_state if link is down - -rtlgen_decode_physr() which sets master_slave_state isn't called in case -the link is down and other than rtlgen_read_status(), -rtl822x_c45_read_status() doesn't implicitely clear master_slave_state. - -Avoid stale master_slave_state by always setting it to -MASTER_SLAVE_STATE_UNKNOWN in rtl822x_c45_read_status() in case the link -is down. - -Fixes: 081c9c0265c9 ("net: phy: realtek: read duplex and gbit master from PHYSR register") -Signed-off-by: Daniel Golle -Reviewed-by: Michal Swiatkowski -Signed-off-by: David S. Miller ---- - drivers/net/phy/realtek.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - ---- a/drivers/net/phy/realtek.c -+++ b/drivers/net/phy/realtek.c -@@ -1038,8 +1038,10 @@ static int rtl822x_c45_read_status(struc - if (ret < 0) - return ret; - -- if (!phydev->link) -+ if (!phydev->link) { -+ phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN; - return 0; -+ } - - /* Read actual speed from vendor register. */ - val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL_VND2_PHYSR); diff --git a/target/linux/generic/backport-6.12/781-22-v6.14-net-phy-realtek-always-clear-NBase-T-lpa.patch b/target/linux/generic/backport-6.12/781-22-v6.14-net-phy-realtek-always-clear-NBase-T-lpa.patch deleted file mode 100644 index d365ed0ad2..0000000000 --- a/target/linux/generic/backport-6.12/781-22-v6.14-net-phy-realtek-always-clear-NBase-T-lpa.patch +++ /dev/null @@ -1,42 +0,0 @@ -From d3eb58549842c60ed46f37da7f4da969e3d6ecd3 Mon Sep 17 00:00:00 2001 -From: Daniel Golle -Date: Wed, 15 Jan 2025 14:45:00 +0000 -Subject: [PATCH] net: phy: realtek: always clear NBase-T lpa - -Clear NBase-T link partner advertisement before calling -rtlgen_read_status() to avoid phy_resolve_aneg_linkmode() wrongly -setting speed and duplex. - -This fixes bogus 2.5G/5G/10G link partner advertisement and thus -speed and duplex being set by phy_resolve_aneg_linkmode() due to stale -NBase-T lpa. - -Fixes: 68d5cd09e891 ("net: phy: realtek: change order of calls in C22 read_status()") -Signed-off-by: Daniel Golle -Reviewed-by: Michal Swiatkowski -Signed-off-by: David S. Miller ---- - drivers/net/phy/realtek.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - ---- a/drivers/net/phy/realtek.c -+++ b/drivers/net/phy/realtek.c -@@ -952,15 +952,15 @@ static int rtl822x_read_status(struct ph - { - int lpadv, ret; - -+ mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, 0); -+ - ret = rtlgen_read_status(phydev); - if (ret < 0) - return ret; - - if (phydev->autoneg == AUTONEG_DISABLE || -- !phydev->autoneg_complete) { -- mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, 0); -+ !phydev->autoneg_complete) - return 0; -- } - - lpadv = phy_read_paged(phydev, 0xa5d, 0x13); - if (lpadv < 0) diff --git a/target/linux/generic/backport-6.12/781-23-v6.14-net-phy-realtek-add-support-for-reading-MDIO_MMD_VEN.patch b/target/linux/generic/backport-6.12/781-23-v6.14-net-phy-realtek-add-support-for-reading-MDIO_MMD_VEN.patch deleted file mode 100644 index 2add672f44..0000000000 --- a/target/linux/generic/backport-6.12/781-23-v6.14-net-phy-realtek-add-support-for-reading-MDIO_MMD_VEN.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 3d483a10327f38595f714f9f9e9dde43a622cb0f Mon Sep 17 00:00:00 2001 -From: Heiner Kallweit -Date: Sat, 11 Jan 2025 21:49:31 +0100 -Subject: [PATCH] net: phy: realtek: add support for reading MDIO_MMD_VEND2 - regs on RTL8125/RTL8126 - -RTL8125/RTL8126 don't support MMD access to the internal PHY, but -provide a mechanism to access at least all MDIO_MMD_VEND2 registers. -By exposing this mechanism standard MMD access functions can be used -to access the MDIO_MMD_VEND2 registers. - -Signed-off-by: Heiner Kallweit -Reviewed-by: Andrew Lunn -Link: https://patch.msgid.link/e821b302-5fe6-49ab-aabd-05da500581c0@gmail.com -Signed-off-by: Jakub Kicinski ---- - drivers/net/phy/realtek.c | 12 ++++++++++-- - 1 file changed, 10 insertions(+), 2 deletions(-) - ---- a/drivers/net/phy/realtek.c -+++ b/drivers/net/phy/realtek.c -@@ -736,7 +736,11 @@ static int rtlgen_read_mmd(struct phy_de - { - int ret; - -- if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) { -+ if (devnum == MDIO_MMD_VEND2) { -+ rtl821x_write_page(phydev, regnum >> 4); -+ ret = __phy_read(phydev, 0x10 + ((regnum & 0xf) >> 1)); -+ rtl821x_write_page(phydev, 0); -+ } else if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) { - rtl821x_write_page(phydev, 0xa5c); - ret = __phy_read(phydev, 0x12); - rtl821x_write_page(phydev, 0); -@@ -760,7 +764,11 @@ static int rtlgen_write_mmd(struct phy_d - { - int ret; - -- if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) { -+ if (devnum == MDIO_MMD_VEND2) { -+ rtl821x_write_page(phydev, regnum >> 4); -+ ret = __phy_write(phydev, 0x10 + ((regnum & 0xf) >> 1), val); -+ rtl821x_write_page(phydev, 0); -+ } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) { - rtl821x_write_page(phydev, 0xa5d); - ret = __phy_write(phydev, 0x10, val); - rtl821x_write_page(phydev, 0); diff --git a/target/linux/generic/backport-6.12/781-24-v6.14-net-phy-move-realtek-PHY-driver-to-its-own-subdirect.patch b/target/linux/generic/backport-6.12/781-24-v6.14-net-phy-move-realtek-PHY-driver-to-its-own-subdirect.patch deleted file mode 100644 index 5f0b61e0ce..0000000000 --- a/target/linux/generic/backport-6.12/781-24-v6.14-net-phy-move-realtek-PHY-driver-to-its-own-subdirect.patch +++ /dev/null @@ -1,3247 +0,0 @@ -From 1416a9b2ba710d31954131c06d46f298e340aa2c Mon Sep 17 00:00:00 2001 -From: Heiner Kallweit -Date: Sat, 11 Jan 2025 21:50:19 +0100 -Subject: [PATCH] net: phy: move realtek PHY driver to its own subdirectory - -In preparation of adding a source file with hwmon support, move the -Realtek PHY driver to its own subdirectory and rename realtek.c to -realtek_main.c. - -Signed-off-by: Heiner Kallweit -Reviewed-by: Andrew Lunn -Link: https://patch.msgid.link/c566551b-c915-4e34-9b33-129a6ddd6e4c@gmail.com -Signed-off-by: Jakub Kicinski ---- - drivers/net/phy/Kconfig | 5 +---- - drivers/net/phy/Makefile | 2 +- - drivers/net/phy/realtek/Kconfig | 5 +++++ - drivers/net/phy/realtek/Makefile | 3 +++ - drivers/net/phy/{realtek.c => realtek/realtek_main.c} | 0 - 5 files changed, 10 insertions(+), 5 deletions(-) - create mode 100644 drivers/net/phy/realtek/Kconfig - create mode 100644 drivers/net/phy/realtek/Makefile - rename drivers/net/phy/{realtek.c => realtek/realtek_main.c} (100%) - ---- a/drivers/net/phy/Kconfig -+++ b/drivers/net/phy/Kconfig -@@ -358,10 +358,7 @@ config QSEMI_PHY - help - Currently supports the qs6612 - --config REALTEK_PHY -- tristate "Realtek PHYs" -- help -- Supports the Realtek 821x PHY. -+source "drivers/net/phy/realtek/Kconfig" - - config RENESAS_PHY - tristate "Renesas PHYs" ---- a/drivers/net/phy/Makefile -+++ b/drivers/net/phy/Makefile -@@ -95,7 +95,7 @@ obj-$(CONFIG_NXP_CBTX_PHY) += nxp-cbtx.o - obj-$(CONFIG_NXP_TJA11XX_PHY) += nxp-tja11xx.o - obj-y += qcom/ - obj-$(CONFIG_QSEMI_PHY) += qsemi.o --obj-$(CONFIG_REALTEK_PHY) += realtek.o -+obj-$(CONFIG_REALTEK_PHY) += realtek/ - obj-$(CONFIG_RENESAS_PHY) += uPD60620.o - obj-$(CONFIG_ROCKCHIP_PHY) += rockchip.o - obj-$(CONFIG_SMSC_PHY) += smsc.o ---- /dev/null -+++ b/drivers/net/phy/realtek/Kconfig -@@ -0,0 +1,5 @@ -+# SPDX-License-Identifier: GPL-2.0-only -+config REALTEK_PHY -+ tristate "Realtek PHYs" -+ help -+ Currently supports RTL821x/RTL822x and fast ethernet PHYs ---- /dev/null -+++ b/drivers/net/phy/realtek/Makefile -@@ -0,0 +1,3 @@ -+# SPDX-License-Identifier: GPL-2.0 -+realtek-y += realtek_main.o -+obj-$(CONFIG_REALTEK_PHY) += realtek.o ---- a/drivers/net/phy/realtek.c -+++ /dev/null -@@ -1,1589 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0+ --/* drivers/net/phy/realtek.c -- * -- * Driver for Realtek PHYs -- * -- * Author: Johnson Leung -- * -- * Copyright (c) 2004 Freescale Semiconductor, Inc. -- */ --#include --#include --#include --#include --#include --#include -- --#define RTL821x_PHYSR 0x11 --#define RTL821x_PHYSR_DUPLEX BIT(13) --#define RTL821x_PHYSR_SPEED GENMASK(15, 14) -- --#define RTL821x_INER 0x12 --#define RTL8211B_INER_INIT 0x6400 --#define RTL8211E_INER_LINK_STATUS BIT(10) --#define RTL8211F_INER_LINK_STATUS BIT(4) -- --#define RTL821x_INSR 0x13 -- --#define RTL821x_EXT_PAGE_SELECT 0x1e --#define RTL821x_PAGE_SELECT 0x1f -- --#define RTL8211F_PHYCR1 0x18 --#define RTL8211F_PHYCR2 0x19 --#define RTL8211F_INSR 0x1d -- --#define RTL8211F_LEDCR 0x10 --#define RTL8211F_LEDCR_MODE BIT(15) --#define RTL8211F_LEDCR_ACT_TXRX BIT(4) --#define RTL8211F_LEDCR_LINK_1000 BIT(3) --#define RTL8211F_LEDCR_LINK_100 BIT(1) --#define RTL8211F_LEDCR_LINK_10 BIT(0) --#define RTL8211F_LEDCR_MASK GENMASK(4, 0) --#define RTL8211F_LEDCR_SHIFT 5 -- --#define RTL8211F_TX_DELAY BIT(8) --#define RTL8211F_RX_DELAY BIT(3) -- --#define RTL8211F_ALDPS_PLL_OFF BIT(1) --#define RTL8211F_ALDPS_ENABLE BIT(2) --#define RTL8211F_ALDPS_XTAL_OFF BIT(12) -- --#define RTL8211E_CTRL_DELAY BIT(13) --#define RTL8211E_TX_DELAY BIT(12) --#define RTL8211E_RX_DELAY BIT(11) -- --#define RTL8211F_CLKOUT_EN BIT(0) -- --#define RTL8201F_ISR 0x1e --#define RTL8201F_ISR_ANERR BIT(15) --#define RTL8201F_ISR_DUPLEX BIT(13) --#define RTL8201F_ISR_LINK BIT(11) --#define RTL8201F_ISR_MASK (RTL8201F_ISR_ANERR | \ -- RTL8201F_ISR_DUPLEX | \ -- RTL8201F_ISR_LINK) --#define RTL8201F_IER 0x13 -- --#define RTL822X_VND1_SERDES_OPTION 0x697a --#define RTL822X_VND1_SERDES_OPTION_MODE_MASK GENMASK(5, 0) --#define RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII 0 --#define RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX 2 -- --#define RTL822X_VND1_SERDES_CTRL3 0x7580 --#define RTL822X_VND1_SERDES_CTRL3_MODE_MASK GENMASK(5, 0) --#define RTL822X_VND1_SERDES_CTRL3_MODE_SGMII 0x02 --#define RTL822X_VND1_SERDES_CTRL3_MODE_2500BASEX 0x16 -- --/* RTL822X_VND2_XXXXX registers are only accessible when phydev->is_c45 -- * is set, they cannot be accessed by C45-over-C22. -- */ --#define RTL822X_VND2_GBCR 0xa412 -- --#define RTL822X_VND2_GANLPAR 0xa414 -- --#define RTL8366RB_POWER_SAVE 0x15 --#define RTL8366RB_POWER_SAVE_ON BIT(12) -- --#define RTL9000A_GINMR 0x14 --#define RTL9000A_GINMR_LINK_STATUS BIT(4) -- --#define RTL_VND2_PHYSR 0xa434 --#define RTL_VND2_PHYSR_DUPLEX BIT(3) --#define RTL_VND2_PHYSR_SPEEDL GENMASK(5, 4) --#define RTL_VND2_PHYSR_SPEEDH GENMASK(10, 9) --#define RTL_VND2_PHYSR_MASTER BIT(11) --#define RTL_VND2_PHYSR_SPEED_MASK (RTL_VND2_PHYSR_SPEEDL | RTL_VND2_PHYSR_SPEEDH) -- --#define RTL_GENERIC_PHYID 0x001cc800 --#define RTL_8211FVD_PHYID 0x001cc878 --#define RTL_8221B 0x001cc840 --#define RTL_8221B_VB_CG 0x001cc849 --#define RTL_8221B_VN_CG 0x001cc84a --#define RTL_8251B 0x001cc862 -- --#define RTL8211F_LED_COUNT 3 -- --MODULE_DESCRIPTION("Realtek PHY driver"); --MODULE_AUTHOR("Johnson Leung"); --MODULE_LICENSE("GPL"); -- --struct rtl821x_priv { -- u16 phycr1; -- u16 phycr2; -- bool has_phycr2; -- struct clk *clk; --}; -- --static int rtl821x_read_page(struct phy_device *phydev) --{ -- return __phy_read(phydev, RTL821x_PAGE_SELECT); --} -- --static int rtl821x_write_page(struct phy_device *phydev, int page) --{ -- return __phy_write(phydev, RTL821x_PAGE_SELECT, page); --} -- --static int rtl821x_probe(struct phy_device *phydev) --{ -- struct device *dev = &phydev->mdio.dev; -- struct rtl821x_priv *priv; -- u32 phy_id = phydev->drv->phy_id; -- int ret; -- -- priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); -- if (!priv) -- return -ENOMEM; -- -- priv->clk = devm_clk_get_optional_enabled(dev, NULL); -- if (IS_ERR(priv->clk)) -- return dev_err_probe(dev, PTR_ERR(priv->clk), -- "failed to get phy clock\n"); -- -- ret = phy_read_paged(phydev, 0xa43, RTL8211F_PHYCR1); -- if (ret < 0) -- return ret; -- -- priv->phycr1 = ret & (RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF); -- if (of_property_read_bool(dev->of_node, "realtek,aldps-enable")) -- priv->phycr1 |= RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF; -- -- priv->has_phycr2 = !(phy_id == RTL_8211FVD_PHYID); -- if (priv->has_phycr2) { -- ret = phy_read_paged(phydev, 0xa43, RTL8211F_PHYCR2); -- if (ret < 0) -- return ret; -- -- priv->phycr2 = ret & RTL8211F_CLKOUT_EN; -- if (of_property_read_bool(dev->of_node, "realtek,clkout-disable")) -- priv->phycr2 &= ~RTL8211F_CLKOUT_EN; -- } -- -- phydev->priv = priv; -- -- return 0; --} -- --static int rtl8201_ack_interrupt(struct phy_device *phydev) --{ -- int err; -- -- err = phy_read(phydev, RTL8201F_ISR); -- -- return (err < 0) ? err : 0; --} -- --static int rtl821x_ack_interrupt(struct phy_device *phydev) --{ -- int err; -- -- err = phy_read(phydev, RTL821x_INSR); -- -- return (err < 0) ? err : 0; --} -- --static int rtl8211f_ack_interrupt(struct phy_device *phydev) --{ -- int err; -- -- err = phy_read_paged(phydev, 0xa43, RTL8211F_INSR); -- -- return (err < 0) ? err : 0; --} -- --static int rtl8201_config_intr(struct phy_device *phydev) --{ -- u16 val; -- int err; -- -- if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { -- err = rtl8201_ack_interrupt(phydev); -- if (err) -- return err; -- -- val = BIT(13) | BIT(12) | BIT(11); -- err = phy_write_paged(phydev, 0x7, RTL8201F_IER, val); -- } else { -- val = 0; -- err = phy_write_paged(phydev, 0x7, RTL8201F_IER, val); -- if (err) -- return err; -- -- err = rtl8201_ack_interrupt(phydev); -- } -- -- return err; --} -- --static int rtl8211b_config_intr(struct phy_device *phydev) --{ -- int err; -- -- if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { -- err = rtl821x_ack_interrupt(phydev); -- if (err) -- return err; -- -- err = phy_write(phydev, RTL821x_INER, -- RTL8211B_INER_INIT); -- } else { -- err = phy_write(phydev, RTL821x_INER, 0); -- if (err) -- return err; -- -- err = rtl821x_ack_interrupt(phydev); -- } -- -- return err; --} -- --static int rtl8211e_config_intr(struct phy_device *phydev) --{ -- int err; -- -- if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { -- err = rtl821x_ack_interrupt(phydev); -- if (err) -- return err; -- -- err = phy_write(phydev, RTL821x_INER, -- RTL8211E_INER_LINK_STATUS); -- } else { -- err = phy_write(phydev, RTL821x_INER, 0); -- if (err) -- return err; -- -- err = rtl821x_ack_interrupt(phydev); -- } -- -- return err; --} -- --static int rtl8211f_config_intr(struct phy_device *phydev) --{ -- u16 val; -- int err; -- -- if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { -- err = rtl8211f_ack_interrupt(phydev); -- if (err) -- return err; -- -- val = RTL8211F_INER_LINK_STATUS; -- err = phy_write_paged(phydev, 0xa42, RTL821x_INER, val); -- } else { -- val = 0; -- err = phy_write_paged(phydev, 0xa42, RTL821x_INER, val); -- if (err) -- return err; -- -- err = rtl8211f_ack_interrupt(phydev); -- } -- -- return err; --} -- --static irqreturn_t rtl8201_handle_interrupt(struct phy_device *phydev) --{ -- int irq_status; -- -- irq_status = phy_read(phydev, RTL8201F_ISR); -- if (irq_status < 0) { -- phy_error(phydev); -- return IRQ_NONE; -- } -- -- if (!(irq_status & RTL8201F_ISR_MASK)) -- return IRQ_NONE; -- -- phy_trigger_machine(phydev); -- -- return IRQ_HANDLED; --} -- --static irqreturn_t rtl821x_handle_interrupt(struct phy_device *phydev) --{ -- int irq_status, irq_enabled; -- -- irq_status = phy_read(phydev, RTL821x_INSR); -- if (irq_status < 0) { -- phy_error(phydev); -- return IRQ_NONE; -- } -- -- irq_enabled = phy_read(phydev, RTL821x_INER); -- if (irq_enabled < 0) { -- phy_error(phydev); -- return IRQ_NONE; -- } -- -- if (!(irq_status & irq_enabled)) -- return IRQ_NONE; -- -- phy_trigger_machine(phydev); -- -- return IRQ_HANDLED; --} -- --static irqreturn_t rtl8211f_handle_interrupt(struct phy_device *phydev) --{ -- int irq_status; -- -- irq_status = phy_read_paged(phydev, 0xa43, RTL8211F_INSR); -- if (irq_status < 0) { -- phy_error(phydev); -- return IRQ_NONE; -- } -- -- if (!(irq_status & RTL8211F_INER_LINK_STATUS)) -- return IRQ_NONE; -- -- phy_trigger_machine(phydev); -- -- return IRQ_HANDLED; --} -- --static int rtl8211_config_aneg(struct phy_device *phydev) --{ -- int ret; -- -- ret = genphy_config_aneg(phydev); -- if (ret < 0) -- return ret; -- -- /* Quirk was copied from vendor driver. Unfortunately it includes no -- * description of the magic numbers. -- */ -- if (phydev->speed == SPEED_100 && phydev->autoneg == AUTONEG_DISABLE) { -- phy_write(phydev, 0x17, 0x2138); -- phy_write(phydev, 0x0e, 0x0260); -- } else { -- phy_write(phydev, 0x17, 0x2108); -- phy_write(phydev, 0x0e, 0x0000); -- } -- -- return 0; --} -- --static int rtl8211c_config_init(struct phy_device *phydev) --{ -- /* RTL8211C has an issue when operating in Gigabit slave mode */ -- return phy_set_bits(phydev, MII_CTRL1000, -- CTL1000_ENABLE_MASTER | CTL1000_AS_MASTER); --} -- --static int rtl8211f_config_init(struct phy_device *phydev) --{ -- struct rtl821x_priv *priv = phydev->priv; -- struct device *dev = &phydev->mdio.dev; -- u16 val_txdly, val_rxdly; -- int ret; -- -- ret = phy_modify_paged_changed(phydev, 0xa43, RTL8211F_PHYCR1, -- RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF, -- priv->phycr1); -- if (ret < 0) { -- dev_err(dev, "aldps mode configuration failed: %pe\n", -- ERR_PTR(ret)); -- return ret; -- } -- -- switch (phydev->interface) { -- case PHY_INTERFACE_MODE_RGMII: -- val_txdly = 0; -- val_rxdly = 0; -- break; -- -- case PHY_INTERFACE_MODE_RGMII_RXID: -- val_txdly = 0; -- val_rxdly = RTL8211F_RX_DELAY; -- break; -- -- case PHY_INTERFACE_MODE_RGMII_TXID: -- val_txdly = RTL8211F_TX_DELAY; -- val_rxdly = 0; -- break; -- -- case PHY_INTERFACE_MODE_RGMII_ID: -- val_txdly = RTL8211F_TX_DELAY; -- val_rxdly = RTL8211F_RX_DELAY; -- break; -- -- default: /* the rest of the modes imply leaving delay as is. */ -- return 0; -- } -- -- ret = phy_modify_paged_changed(phydev, 0xd08, 0x11, RTL8211F_TX_DELAY, -- val_txdly); -- if (ret < 0) { -- dev_err(dev, "Failed to update the TX delay register\n"); -- return ret; -- } else if (ret) { -- dev_dbg(dev, -- "%s 2ns TX delay (and changing the value from pin-strapping RXD1 or the bootloader)\n", -- val_txdly ? "Enabling" : "Disabling"); -- } else { -- dev_dbg(dev, -- "2ns TX delay was already %s (by pin-strapping RXD1 or bootloader configuration)\n", -- val_txdly ? "enabled" : "disabled"); -- } -- -- ret = phy_modify_paged_changed(phydev, 0xd08, 0x15, RTL8211F_RX_DELAY, -- val_rxdly); -- if (ret < 0) { -- dev_err(dev, "Failed to update the RX delay register\n"); -- return ret; -- } else if (ret) { -- dev_dbg(dev, -- "%s 2ns RX delay (and changing the value from pin-strapping RXD0 or the bootloader)\n", -- val_rxdly ? "Enabling" : "Disabling"); -- } else { -- dev_dbg(dev, -- "2ns RX delay was already %s (by pin-strapping RXD0 or bootloader configuration)\n", -- val_rxdly ? "enabled" : "disabled"); -- } -- -- if (priv->has_phycr2) { -- ret = phy_modify_paged(phydev, 0xa43, RTL8211F_PHYCR2, -- RTL8211F_CLKOUT_EN, priv->phycr2); -- if (ret < 0) { -- dev_err(dev, "clkout configuration failed: %pe\n", -- ERR_PTR(ret)); -- return ret; -- } -- -- return genphy_soft_reset(phydev); -- } -- -- return 0; --} -- --static int rtl821x_suspend(struct phy_device *phydev) --{ -- struct rtl821x_priv *priv = phydev->priv; -- int ret = 0; -- -- if (!phydev->wol_enabled) { -- ret = genphy_suspend(phydev); -- -- if (ret) -- return ret; -- -- clk_disable_unprepare(priv->clk); -- } -- -- return ret; --} -- --static int rtl821x_resume(struct phy_device *phydev) --{ -- struct rtl821x_priv *priv = phydev->priv; -- int ret; -- -- if (!phydev->wol_enabled) -- clk_prepare_enable(priv->clk); -- -- ret = genphy_resume(phydev); -- if (ret < 0) -- return ret; -- -- msleep(20); -- -- return 0; --} -- --static int rtl8211f_led_hw_is_supported(struct phy_device *phydev, u8 index, -- unsigned long rules) --{ -- const unsigned long mask = BIT(TRIGGER_NETDEV_LINK_10) | -- BIT(TRIGGER_NETDEV_LINK_100) | -- BIT(TRIGGER_NETDEV_LINK_1000) | -- BIT(TRIGGER_NETDEV_RX) | -- BIT(TRIGGER_NETDEV_TX); -- -- /* The RTL8211F PHY supports these LED settings on up to three LEDs: -- * - Link: Configurable subset of 10/100/1000 link rates -- * - Active: Blink on activity, RX or TX is not differentiated -- * The Active option has two modes, A and B: -- * - A: Link and Active indication at configurable, but matching, -- * subset of 10/100/1000 link rates -- * - B: Link indication at configurable subset of 10/100/1000 link -- * rates and Active indication always at all three 10+100+1000 -- * link rates. -- * This code currently uses mode B only. -- */ -- -- if (index >= RTL8211F_LED_COUNT) -- return -EINVAL; -- -- /* Filter out any other unsupported triggers. */ -- if (rules & ~mask) -- return -EOPNOTSUPP; -- -- /* RX and TX are not differentiated, either both are set or not set. */ -- if (!(rules & BIT(TRIGGER_NETDEV_RX)) ^ !(rules & BIT(TRIGGER_NETDEV_TX))) -- return -EOPNOTSUPP; -- -- return 0; --} -- --static int rtl8211f_led_hw_control_get(struct phy_device *phydev, u8 index, -- unsigned long *rules) --{ -- int val; -- -- if (index >= RTL8211F_LED_COUNT) -- return -EINVAL; -- -- val = phy_read_paged(phydev, 0xd04, RTL8211F_LEDCR); -- if (val < 0) -- return val; -- -- val >>= RTL8211F_LEDCR_SHIFT * index; -- val &= RTL8211F_LEDCR_MASK; -- -- if (val & RTL8211F_LEDCR_LINK_10) -- set_bit(TRIGGER_NETDEV_LINK_10, rules); -- -- if (val & RTL8211F_LEDCR_LINK_100) -- set_bit(TRIGGER_NETDEV_LINK_100, rules); -- -- if (val & RTL8211F_LEDCR_LINK_1000) -- set_bit(TRIGGER_NETDEV_LINK_1000, rules); -- -- if (val & RTL8211F_LEDCR_ACT_TXRX) { -- set_bit(TRIGGER_NETDEV_RX, rules); -- set_bit(TRIGGER_NETDEV_TX, rules); -- } -- -- return 0; --} -- --static int rtl8211f_led_hw_control_set(struct phy_device *phydev, u8 index, -- unsigned long rules) --{ -- const u16 mask = RTL8211F_LEDCR_MASK << (RTL8211F_LEDCR_SHIFT * index); -- u16 reg = 0; -- -- if (index >= RTL8211F_LED_COUNT) -- return -EINVAL; -- -- if (test_bit(TRIGGER_NETDEV_LINK_10, &rules)) -- reg |= RTL8211F_LEDCR_LINK_10; -- -- if (test_bit(TRIGGER_NETDEV_LINK_100, &rules)) -- reg |= RTL8211F_LEDCR_LINK_100; -- -- if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules)) -- reg |= RTL8211F_LEDCR_LINK_1000; -- -- if (test_bit(TRIGGER_NETDEV_RX, &rules) || -- test_bit(TRIGGER_NETDEV_TX, &rules)) { -- reg |= RTL8211F_LEDCR_ACT_TXRX; -- } -- -- reg <<= RTL8211F_LEDCR_SHIFT * index; -- reg |= RTL8211F_LEDCR_MODE; /* Mode B */ -- -- return phy_modify_paged(phydev, 0xd04, RTL8211F_LEDCR, mask, reg); --} -- --static int rtl8211e_config_init(struct phy_device *phydev) --{ -- int ret = 0, oldpage; -- u16 val; -- -- /* enable TX/RX delay for rgmii-* modes, and disable them for rgmii. */ -- switch (phydev->interface) { -- case PHY_INTERFACE_MODE_RGMII: -- val = RTL8211E_CTRL_DELAY | 0; -- break; -- case PHY_INTERFACE_MODE_RGMII_ID: -- val = RTL8211E_CTRL_DELAY | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY; -- break; -- case PHY_INTERFACE_MODE_RGMII_RXID: -- val = RTL8211E_CTRL_DELAY | RTL8211E_RX_DELAY; -- break; -- case PHY_INTERFACE_MODE_RGMII_TXID: -- val = RTL8211E_CTRL_DELAY | RTL8211E_TX_DELAY; -- break; -- default: /* the rest of the modes imply leaving delays as is. */ -- return 0; -- } -- -- /* According to a sample driver there is a 0x1c config register on the -- * 0xa4 extension page (0x7) layout. It can be used to disable/enable -- * the RX/TX delays otherwise controlled by RXDLY/TXDLY pins. -- * The configuration register definition: -- * 14 = reserved -- * 13 = Force Tx RX Delay controlled by bit12 bit11, -- * 12 = RX Delay, 11 = TX Delay -- * 10:0 = Test && debug settings reserved by realtek -- */ -- oldpage = phy_select_page(phydev, 0x7); -- if (oldpage < 0) -- goto err_restore_page; -- -- ret = __phy_write(phydev, RTL821x_EXT_PAGE_SELECT, 0xa4); -- if (ret) -- goto err_restore_page; -- -- ret = __phy_modify(phydev, 0x1c, RTL8211E_CTRL_DELAY -- | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY, -- val); -- --err_restore_page: -- return phy_restore_page(phydev, oldpage, ret); --} -- --static int rtl8211b_suspend(struct phy_device *phydev) --{ -- phy_write(phydev, MII_MMD_DATA, BIT(9)); -- -- return genphy_suspend(phydev); --} -- --static int rtl8211b_resume(struct phy_device *phydev) --{ -- phy_write(phydev, MII_MMD_DATA, 0); -- -- return genphy_resume(phydev); --} -- --static int rtl8366rb_config_init(struct phy_device *phydev) --{ -- int ret; -- -- ret = phy_set_bits(phydev, RTL8366RB_POWER_SAVE, -- RTL8366RB_POWER_SAVE_ON); -- if (ret) { -- dev_err(&phydev->mdio.dev, -- "error enabling power management\n"); -- } -- -- return ret; --} -- --/* get actual speed to cover the downshift case */ --static void rtlgen_decode_physr(struct phy_device *phydev, int val) --{ -- /* bit 3 -- * 0: Half Duplex -- * 1: Full Duplex -- */ -- if (val & RTL_VND2_PHYSR_DUPLEX) -- phydev->duplex = DUPLEX_FULL; -- else -- phydev->duplex = DUPLEX_HALF; -- -- switch (val & RTL_VND2_PHYSR_SPEED_MASK) { -- case 0x0000: -- phydev->speed = SPEED_10; -- break; -- case 0x0010: -- phydev->speed = SPEED_100; -- break; -- case 0x0020: -- phydev->speed = SPEED_1000; -- break; -- case 0x0200: -- phydev->speed = SPEED_10000; -- break; -- case 0x0210: -- phydev->speed = SPEED_2500; -- break; -- case 0x0220: -- phydev->speed = SPEED_5000; -- break; -- default: -- break; -- } -- -- /* bit 11 -- * 0: Slave Mode -- * 1: Master Mode -- */ -- if (phydev->speed >= 1000) { -- if (val & RTL_VND2_PHYSR_MASTER) -- phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER; -- else -- phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE; -- } else { -- phydev->master_slave_state = MASTER_SLAVE_STATE_UNSUPPORTED; -- } --} -- --static int rtlgen_read_status(struct phy_device *phydev) --{ -- int ret, val; -- -- ret = genphy_read_status(phydev); -- if (ret < 0) -- return ret; -- -- if (!phydev->link) -- return 0; -- -- val = phy_read_paged(phydev, 0xa43, 0x12); -- if (val < 0) -- return val; -- -- rtlgen_decode_physr(phydev, val); -- -- return 0; --} -- --static int rtlgen_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) --{ -- int ret; -- -- if (devnum == MDIO_MMD_VEND2) { -- rtl821x_write_page(phydev, regnum >> 4); -- ret = __phy_read(phydev, 0x10 + ((regnum & 0xf) >> 1)); -- rtl821x_write_page(phydev, 0); -- } else if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) { -- rtl821x_write_page(phydev, 0xa5c); -- ret = __phy_read(phydev, 0x12); -- rtl821x_write_page(phydev, 0); -- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) { -- rtl821x_write_page(phydev, 0xa5d); -- ret = __phy_read(phydev, 0x10); -- rtl821x_write_page(phydev, 0); -- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE) { -- rtl821x_write_page(phydev, 0xa5d); -- ret = __phy_read(phydev, 0x11); -- rtl821x_write_page(phydev, 0); -- } else { -- ret = -EOPNOTSUPP; -- } -- -- return ret; --} -- --static int rtlgen_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, -- u16 val) --{ -- int ret; -- -- if (devnum == MDIO_MMD_VEND2) { -- rtl821x_write_page(phydev, regnum >> 4); -- ret = __phy_write(phydev, 0x10 + ((regnum & 0xf) >> 1), val); -- rtl821x_write_page(phydev, 0); -- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) { -- rtl821x_write_page(phydev, 0xa5d); -- ret = __phy_write(phydev, 0x10, val); -- rtl821x_write_page(phydev, 0); -- } else { -- ret = -EOPNOTSUPP; -- } -- -- return ret; --} -- --static int rtl822x_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) --{ -- int ret = rtlgen_read_mmd(phydev, devnum, regnum); -- -- if (ret != -EOPNOTSUPP) -- return ret; -- -- if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE2) { -- rtl821x_write_page(phydev, 0xa6e); -- ret = __phy_read(phydev, 0x16); -- rtl821x_write_page(phydev, 0); -- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) { -- rtl821x_write_page(phydev, 0xa6d); -- ret = __phy_read(phydev, 0x12); -- rtl821x_write_page(phydev, 0); -- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE2) { -- rtl821x_write_page(phydev, 0xa6d); -- ret = __phy_read(phydev, 0x10); -- rtl821x_write_page(phydev, 0); -- } -- -- return ret; --} -- --static int rtl822x_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, -- u16 val) --{ -- int ret = rtlgen_write_mmd(phydev, devnum, regnum, val); -- -- if (ret != -EOPNOTSUPP) -- return ret; -- -- if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) { -- rtl821x_write_page(phydev, 0xa6d); -- ret = __phy_write(phydev, 0x12, val); -- rtl821x_write_page(phydev, 0); -- } -- -- return ret; --} -- --static int rtl822xb_config_init(struct phy_device *phydev) --{ -- bool has_2500, has_sgmii; -- u16 mode; -- int ret; -- -- has_2500 = test_bit(PHY_INTERFACE_MODE_2500BASEX, -- phydev->host_interfaces) || -- phydev->interface == PHY_INTERFACE_MODE_2500BASEX; -- -- has_sgmii = test_bit(PHY_INTERFACE_MODE_SGMII, -- phydev->host_interfaces) || -- phydev->interface == PHY_INTERFACE_MODE_SGMII; -- -- /* fill in possible interfaces */ -- __assign_bit(PHY_INTERFACE_MODE_2500BASEX, phydev->possible_interfaces, -- has_2500); -- __assign_bit(PHY_INTERFACE_MODE_SGMII, phydev->possible_interfaces, -- has_sgmii); -- -- if (!has_2500 && !has_sgmii) -- return 0; -- -- /* determine SerDes option mode */ -- if (has_2500 && !has_sgmii) { -- mode = RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX; -- phydev->rate_matching = RATE_MATCH_PAUSE; -- } else { -- mode = RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII; -- phydev->rate_matching = RATE_MATCH_NONE; -- } -- -- /* the following sequence with magic numbers sets up the SerDes -- * option mode -- */ -- ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x75f3, 0); -- if (ret < 0) -- return ret; -- -- ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND1, -- RTL822X_VND1_SERDES_OPTION, -- RTL822X_VND1_SERDES_OPTION_MODE_MASK, -- mode); -- if (ret < 0) -- return ret; -- -- ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6a04, 0x0503); -- if (ret < 0) -- return ret; -- -- ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f10, 0xd455); -- if (ret < 0) -- return ret; -- -- return phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f11, 0x8020); --} -- --static int rtl822xb_get_rate_matching(struct phy_device *phydev, -- phy_interface_t iface) --{ -- int val; -- -- /* Only rate matching at 2500base-x */ -- if (iface != PHY_INTERFACE_MODE_2500BASEX) -- return RATE_MATCH_NONE; -- -- val = phy_read_mmd(phydev, MDIO_MMD_VEND1, RTL822X_VND1_SERDES_OPTION); -- if (val < 0) -- return val; -- -- if ((val & RTL822X_VND1_SERDES_OPTION_MODE_MASK) == -- RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX) -- return RATE_MATCH_PAUSE; -- -- /* RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII */ -- return RATE_MATCH_NONE; --} -- --static int rtl822x_get_features(struct phy_device *phydev) --{ -- int val; -- -- val = phy_read_paged(phydev, 0xa61, 0x13); -- if (val < 0) -- return val; -- -- linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, -- phydev->supported, val & MDIO_PMA_SPEED_2_5G); -- linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, -- phydev->supported, val & MDIO_PMA_SPEED_5G); -- linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, -- phydev->supported, val & MDIO_SPEED_10G); -- -- return genphy_read_abilities(phydev); --} -- --static int rtl822x_config_aneg(struct phy_device *phydev) --{ -- int ret = 0; -- -- if (phydev->autoneg == AUTONEG_ENABLE) { -- u16 adv = linkmode_adv_to_mii_10gbt_adv_t(phydev->advertising); -- -- ret = phy_modify_paged_changed(phydev, 0xa5d, 0x12, -- MDIO_AN_10GBT_CTRL_ADV2_5G | -- MDIO_AN_10GBT_CTRL_ADV5G, -- adv); -- if (ret < 0) -- return ret; -- } -- -- return __genphy_config_aneg(phydev, ret); --} -- --static void rtl822xb_update_interface(struct phy_device *phydev) --{ -- int val; -- -- if (!phydev->link) -- return; -- -- /* Change interface according to serdes mode */ -- val = phy_read_mmd(phydev, MDIO_MMD_VEND1, RTL822X_VND1_SERDES_CTRL3); -- if (val < 0) -- return; -- -- switch (val & RTL822X_VND1_SERDES_CTRL3_MODE_MASK) { -- case RTL822X_VND1_SERDES_CTRL3_MODE_2500BASEX: -- phydev->interface = PHY_INTERFACE_MODE_2500BASEX; -- break; -- case RTL822X_VND1_SERDES_CTRL3_MODE_SGMII: -- phydev->interface = PHY_INTERFACE_MODE_SGMII; -- break; -- } --} -- --static int rtl822x_read_status(struct phy_device *phydev) --{ -- int lpadv, ret; -- -- mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, 0); -- -- ret = rtlgen_read_status(phydev); -- if (ret < 0) -- return ret; -- -- if (phydev->autoneg == AUTONEG_DISABLE || -- !phydev->autoneg_complete) -- return 0; -- -- lpadv = phy_read_paged(phydev, 0xa5d, 0x13); -- if (lpadv < 0) -- return lpadv; -- -- mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, lpadv); -- -- return 0; --} -- --static int rtl822xb_read_status(struct phy_device *phydev) --{ -- int ret; -- -- ret = rtl822x_read_status(phydev); -- if (ret < 0) -- return ret; -- -- rtl822xb_update_interface(phydev); -- -- return 0; --} -- --static int rtl822x_c45_get_features(struct phy_device *phydev) --{ -- linkmode_set_bit(ETHTOOL_LINK_MODE_TP_BIT, -- phydev->supported); -- -- return genphy_c45_pma_read_abilities(phydev); --} -- --static int rtl822x_c45_config_aneg(struct phy_device *phydev) --{ -- bool changed = false; -- int ret, val; -- -- if (phydev->autoneg == AUTONEG_DISABLE) -- return genphy_c45_pma_setup_forced(phydev); -- -- ret = genphy_c45_an_config_aneg(phydev); -- if (ret < 0) -- return ret; -- if (ret > 0) -- changed = true; -- -- val = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising); -- -- /* Vendor register as C45 has no standardized support for 1000BaseT */ -- ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, RTL822X_VND2_GBCR, -- ADVERTISE_1000FULL, val); -- if (ret < 0) -- return ret; -- if (ret > 0) -- changed = true; -- -- return genphy_c45_check_and_restart_aneg(phydev, changed); --} -- --static int rtl822x_c45_read_status(struct phy_device *phydev) --{ -- int ret, val; -- -- /* Vendor register as C45 has no standardized support for 1000BaseT */ -- if (phydev->autoneg == AUTONEG_ENABLE && genphy_c45_aneg_done(phydev)) { -- val = phy_read_mmd(phydev, MDIO_MMD_VEND2, -- RTL822X_VND2_GANLPAR); -- if (val < 0) -- return val; -- } else { -- val = 0; -- } -- mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, val); -- -- ret = genphy_c45_read_status(phydev); -- if (ret < 0) -- return ret; -- -- if (!phydev->link) { -- phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN; -- return 0; -- } -- -- /* Read actual speed from vendor register. */ -- val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL_VND2_PHYSR); -- if (val < 0) -- return val; -- -- rtlgen_decode_physr(phydev, val); -- -- return 0; --} -- --static int rtl822xb_c45_read_status(struct phy_device *phydev) --{ -- int ret; -- -- ret = rtl822x_c45_read_status(phydev); -- if (ret < 0) -- return ret; -- -- rtl822xb_update_interface(phydev); -- -- return 0; --} -- --static bool rtlgen_supports_2_5gbps(struct phy_device *phydev) --{ -- int val; -- -- phy_write(phydev, RTL821x_PAGE_SELECT, 0xa61); -- val = phy_read(phydev, 0x13); -- phy_write(phydev, RTL821x_PAGE_SELECT, 0); -- -- return val >= 0 && val & MDIO_PMA_SPEED_2_5G; --} -- --/* On internal PHY's MMD reads over C22 always return 0. -- * Check a MMD register which is known to be non-zero. -- */ --static bool rtlgen_supports_mmd(struct phy_device *phydev) --{ -- int val; -- -- phy_lock_mdio_bus(phydev); -- __phy_write(phydev, MII_MMD_CTRL, MDIO_MMD_PCS); -- __phy_write(phydev, MII_MMD_DATA, MDIO_PCS_EEE_ABLE); -- __phy_write(phydev, MII_MMD_CTRL, MDIO_MMD_PCS | MII_MMD_CTRL_NOINCR); -- val = __phy_read(phydev, MII_MMD_DATA); -- phy_unlock_mdio_bus(phydev); -- -- return val > 0; --} -- --static int rtlgen_match_phy_device(struct phy_device *phydev) --{ -- return phydev->phy_id == RTL_GENERIC_PHYID && -- !rtlgen_supports_2_5gbps(phydev); --} -- --static int rtl8226_match_phy_device(struct phy_device *phydev) --{ -- return phydev->phy_id == RTL_GENERIC_PHYID && -- rtlgen_supports_2_5gbps(phydev) && -- rtlgen_supports_mmd(phydev); --} -- --static int rtlgen_is_c45_match(struct phy_device *phydev, unsigned int id, -- bool is_c45) --{ -- if (phydev->is_c45) -- return is_c45 && (id == phydev->c45_ids.device_ids[1]); -- else -- return !is_c45 && (id == phydev->phy_id); --} -- --static int rtl8221b_match_phy_device(struct phy_device *phydev) --{ -- return phydev->phy_id == RTL_8221B && rtlgen_supports_mmd(phydev); --} -- --static int rtl8221b_vb_cg_c22_match_phy_device(struct phy_device *phydev) --{ -- return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, false); --} -- --static int rtl8221b_vb_cg_c45_match_phy_device(struct phy_device *phydev) --{ -- return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, true); --} -- --static int rtl8221b_vn_cg_c22_match_phy_device(struct phy_device *phydev) --{ -- return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, false); --} -- --static int rtl8221b_vn_cg_c45_match_phy_device(struct phy_device *phydev) --{ -- return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, true); --} -- --static int rtl_internal_nbaset_match_phy_device(struct phy_device *phydev) --{ -- if (phydev->is_c45) -- return false; -- -- switch (phydev->phy_id) { -- case RTL_GENERIC_PHYID: -- case RTL_8221B: -- case RTL_8251B: -- case 0x001cc841: -- break; -- default: -- return false; -- } -- -- return rtlgen_supports_2_5gbps(phydev) && !rtlgen_supports_mmd(phydev); --} -- --static int rtl8251b_c45_match_phy_device(struct phy_device *phydev) --{ -- return rtlgen_is_c45_match(phydev, RTL_8251B, true); --} -- --static int rtlgen_resume(struct phy_device *phydev) --{ -- int ret = genphy_resume(phydev); -- -- /* Internal PHY's from RTL8168h up may not be instantly ready */ -- msleep(20); -- -- return ret; --} -- --static int rtlgen_c45_resume(struct phy_device *phydev) --{ -- int ret = genphy_c45_pma_resume(phydev); -- -- msleep(20); -- -- return ret; --} -- --static int rtl9000a_config_init(struct phy_device *phydev) --{ -- phydev->autoneg = AUTONEG_DISABLE; -- phydev->speed = SPEED_100; -- phydev->duplex = DUPLEX_FULL; -- -- return 0; --} -- --static int rtl9000a_config_aneg(struct phy_device *phydev) --{ -- int ret; -- u16 ctl = 0; -- -- switch (phydev->master_slave_set) { -- case MASTER_SLAVE_CFG_MASTER_FORCE: -- ctl |= CTL1000_AS_MASTER; -- break; -- case MASTER_SLAVE_CFG_SLAVE_FORCE: -- break; -- case MASTER_SLAVE_CFG_UNKNOWN: -- case MASTER_SLAVE_CFG_UNSUPPORTED: -- return 0; -- default: -- phydev_warn(phydev, "Unsupported Master/Slave mode\n"); -- return -EOPNOTSUPP; -- } -- -- ret = phy_modify_changed(phydev, MII_CTRL1000, CTL1000_AS_MASTER, ctl); -- if (ret == 1) -- ret = genphy_soft_reset(phydev); -- -- return ret; --} -- --static int rtl9000a_read_status(struct phy_device *phydev) --{ -- int ret; -- -- phydev->master_slave_get = MASTER_SLAVE_CFG_UNKNOWN; -- phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN; -- -- ret = genphy_update_link(phydev); -- if (ret) -- return ret; -- -- ret = phy_read(phydev, MII_CTRL1000); -- if (ret < 0) -- return ret; -- if (ret & CTL1000_AS_MASTER) -- phydev->master_slave_get = MASTER_SLAVE_CFG_MASTER_FORCE; -- else -- phydev->master_slave_get = MASTER_SLAVE_CFG_SLAVE_FORCE; -- -- ret = phy_read(phydev, MII_STAT1000); -- if (ret < 0) -- return ret; -- if (ret & LPA_1000MSRES) -- phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER; -- else -- phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE; -- -- return 0; --} -- --static int rtl9000a_ack_interrupt(struct phy_device *phydev) --{ -- int err; -- -- err = phy_read(phydev, RTL8211F_INSR); -- -- return (err < 0) ? err : 0; --} -- --static int rtl9000a_config_intr(struct phy_device *phydev) --{ -- u16 val; -- int err; -- -- if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { -- err = rtl9000a_ack_interrupt(phydev); -- if (err) -- return err; -- -- val = (u16)~RTL9000A_GINMR_LINK_STATUS; -- err = phy_write_paged(phydev, 0xa42, RTL9000A_GINMR, val); -- } else { -- val = ~0; -- err = phy_write_paged(phydev, 0xa42, RTL9000A_GINMR, val); -- if (err) -- return err; -- -- err = rtl9000a_ack_interrupt(phydev); -- } -- -- return phy_write_paged(phydev, 0xa42, RTL9000A_GINMR, val); --} -- --static irqreturn_t rtl9000a_handle_interrupt(struct phy_device *phydev) --{ -- int irq_status; -- -- irq_status = phy_read(phydev, RTL8211F_INSR); -- if (irq_status < 0) { -- phy_error(phydev); -- return IRQ_NONE; -- } -- -- if (!(irq_status & RTL8211F_INER_LINK_STATUS)) -- return IRQ_NONE; -- -- phy_trigger_machine(phydev); -- -- return IRQ_HANDLED; --} -- --static struct phy_driver realtek_drvs[] = { -- { -- PHY_ID_MATCH_EXACT(0x00008201), -- .name = "RTL8201CP Ethernet", -- .read_page = rtl821x_read_page, -- .write_page = rtl821x_write_page, -- }, { -- PHY_ID_MATCH_EXACT(0x001cc816), -- .name = "RTL8201F Fast Ethernet", -- .config_intr = &rtl8201_config_intr, -- .handle_interrupt = rtl8201_handle_interrupt, -- .suspend = genphy_suspend, -- .resume = genphy_resume, -- .read_page = rtl821x_read_page, -- .write_page = rtl821x_write_page, -- }, { -- PHY_ID_MATCH_MODEL(0x001cc880), -- .name = "RTL8208 Fast Ethernet", -- .read_mmd = genphy_read_mmd_unsupported, -- .write_mmd = genphy_write_mmd_unsupported, -- .suspend = genphy_suspend, -- .resume = genphy_resume, -- .read_page = rtl821x_read_page, -- .write_page = rtl821x_write_page, -- }, { -- PHY_ID_MATCH_EXACT(0x001cc910), -- .name = "RTL8211 Gigabit Ethernet", -- .config_aneg = rtl8211_config_aneg, -- .read_mmd = &genphy_read_mmd_unsupported, -- .write_mmd = &genphy_write_mmd_unsupported, -- .read_page = rtl821x_read_page, -- .write_page = rtl821x_write_page, -- }, { -- PHY_ID_MATCH_EXACT(0x001cc912), -- .name = "RTL8211B Gigabit Ethernet", -- .config_intr = &rtl8211b_config_intr, -- .handle_interrupt = rtl821x_handle_interrupt, -- .read_mmd = &genphy_read_mmd_unsupported, -- .write_mmd = &genphy_write_mmd_unsupported, -- .suspend = rtl8211b_suspend, -- .resume = rtl8211b_resume, -- .read_page = rtl821x_read_page, -- .write_page = rtl821x_write_page, -- }, { -- PHY_ID_MATCH_EXACT(0x001cc913), -- .name = "RTL8211C Gigabit Ethernet", -- .config_init = rtl8211c_config_init, -- .read_mmd = &genphy_read_mmd_unsupported, -- .write_mmd = &genphy_write_mmd_unsupported, -- .read_page = rtl821x_read_page, -- .write_page = rtl821x_write_page, -- }, { -- PHY_ID_MATCH_EXACT(0x001cc914), -- .name = "RTL8211DN Gigabit Ethernet", -- .config_intr = rtl8211e_config_intr, -- .handle_interrupt = rtl821x_handle_interrupt, -- .suspend = genphy_suspend, -- .resume = genphy_resume, -- .read_page = rtl821x_read_page, -- .write_page = rtl821x_write_page, -- }, { -- PHY_ID_MATCH_EXACT(0x001cc915), -- .name = "RTL8211E Gigabit Ethernet", -- .config_init = &rtl8211e_config_init, -- .config_intr = &rtl8211e_config_intr, -- .handle_interrupt = rtl821x_handle_interrupt, -- .suspend = genphy_suspend, -- .resume = genphy_resume, -- .read_page = rtl821x_read_page, -- .write_page = rtl821x_write_page, -- }, { -- PHY_ID_MATCH_EXACT(0x001cc916), -- .name = "RTL8211F Gigabit Ethernet", -- .probe = rtl821x_probe, -- .config_init = &rtl8211f_config_init, -- .read_status = rtlgen_read_status, -- .config_intr = &rtl8211f_config_intr, -- .handle_interrupt = rtl8211f_handle_interrupt, -- .suspend = rtl821x_suspend, -- .resume = rtl821x_resume, -- .read_page = rtl821x_read_page, -- .write_page = rtl821x_write_page, -- .flags = PHY_ALWAYS_CALL_SUSPEND, -- .led_hw_is_supported = rtl8211f_led_hw_is_supported, -- .led_hw_control_get = rtl8211f_led_hw_control_get, -- .led_hw_control_set = rtl8211f_led_hw_control_set, -- }, { -- PHY_ID_MATCH_EXACT(RTL_8211FVD_PHYID), -- .name = "RTL8211F-VD Gigabit Ethernet", -- .probe = rtl821x_probe, -- .config_init = &rtl8211f_config_init, -- .read_status = rtlgen_read_status, -- .config_intr = &rtl8211f_config_intr, -- .handle_interrupt = rtl8211f_handle_interrupt, -- .suspend = rtl821x_suspend, -- .resume = rtl821x_resume, -- .read_page = rtl821x_read_page, -- .write_page = rtl821x_write_page, -- .flags = PHY_ALWAYS_CALL_SUSPEND, -- }, { -- .name = "Generic FE-GE Realtek PHY", -- .match_phy_device = rtlgen_match_phy_device, -- .read_status = rtlgen_read_status, -- .suspend = genphy_suspend, -- .resume = rtlgen_resume, -- .read_page = rtl821x_read_page, -- .write_page = rtl821x_write_page, -- .read_mmd = rtlgen_read_mmd, -- .write_mmd = rtlgen_write_mmd, -- }, { -- .name = "RTL8226 2.5Gbps PHY", -- .match_phy_device = rtl8226_match_phy_device, -- .get_features = rtl822x_get_features, -- .config_aneg = rtl822x_config_aneg, -- .read_status = rtl822x_read_status, -- .suspend = genphy_suspend, -- .resume = rtlgen_resume, -- .read_page = rtl821x_read_page, -- .write_page = rtl821x_write_page, -- }, { -- .match_phy_device = rtl8221b_match_phy_device, -- .name = "RTL8226B_RTL8221B 2.5Gbps PHY", -- .get_features = rtl822x_get_features, -- .config_aneg = rtl822x_config_aneg, -- .config_init = rtl822xb_config_init, -- .get_rate_matching = rtl822xb_get_rate_matching, -- .read_status = rtl822xb_read_status, -- .suspend = genphy_suspend, -- .resume = rtlgen_resume, -- .read_page = rtl821x_read_page, -- .write_page = rtl821x_write_page, -- }, { -- PHY_ID_MATCH_EXACT(0x001cc838), -- .name = "RTL8226-CG 2.5Gbps PHY", -- .get_features = rtl822x_get_features, -- .config_aneg = rtl822x_config_aneg, -- .read_status = rtl822x_read_status, -- .suspend = genphy_suspend, -- .resume = rtlgen_resume, -- .read_page = rtl821x_read_page, -- .write_page = rtl821x_write_page, -- }, { -- PHY_ID_MATCH_EXACT(0x001cc848), -- .name = "RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY", -- .get_features = rtl822x_get_features, -- .config_aneg = rtl822x_config_aneg, -- .config_init = rtl822xb_config_init, -- .get_rate_matching = rtl822xb_get_rate_matching, -- .read_status = rtl822xb_read_status, -- .suspend = genphy_suspend, -- .resume = rtlgen_resume, -- .read_page = rtl821x_read_page, -- .write_page = rtl821x_write_page, -- }, { -- .match_phy_device = rtl8221b_vb_cg_c22_match_phy_device, -- .name = "RTL8221B-VB-CG 2.5Gbps PHY (C22)", -- .get_features = rtl822x_get_features, -- .config_aneg = rtl822x_config_aneg, -- .config_init = rtl822xb_config_init, -- .get_rate_matching = rtl822xb_get_rate_matching, -- .read_status = rtl822xb_read_status, -- .suspend = genphy_suspend, -- .resume = rtlgen_resume, -- .read_page = rtl821x_read_page, -- .write_page = rtl821x_write_page, -- }, { -- .match_phy_device = rtl8221b_vb_cg_c45_match_phy_device, -- .name = "RTL8221B-VB-CG 2.5Gbps PHY (C45)", -- .config_init = rtl822xb_config_init, -- .get_rate_matching = rtl822xb_get_rate_matching, -- .get_features = rtl822x_c45_get_features, -- .config_aneg = rtl822x_c45_config_aneg, -- .read_status = rtl822xb_c45_read_status, -- .suspend = genphy_c45_pma_suspend, -- .resume = rtlgen_c45_resume, -- }, { -- .match_phy_device = rtl8221b_vn_cg_c22_match_phy_device, -- .name = "RTL8221B-VM-CG 2.5Gbps PHY (C22)", -- .get_features = rtl822x_get_features, -- .config_aneg = rtl822x_config_aneg, -- .config_init = rtl822xb_config_init, -- .get_rate_matching = rtl822xb_get_rate_matching, -- .read_status = rtl822xb_read_status, -- .suspend = genphy_suspend, -- .resume = rtlgen_resume, -- .read_page = rtl821x_read_page, -- .write_page = rtl821x_write_page, -- }, { -- .match_phy_device = rtl8221b_vn_cg_c45_match_phy_device, -- .name = "RTL8221B-VN-CG 2.5Gbps PHY (C45)", -- .config_init = rtl822xb_config_init, -- .get_rate_matching = rtl822xb_get_rate_matching, -- .get_features = rtl822x_c45_get_features, -- .config_aneg = rtl822x_c45_config_aneg, -- .read_status = rtl822xb_c45_read_status, -- .suspend = genphy_c45_pma_suspend, -- .resume = rtlgen_c45_resume, -- }, { -- .match_phy_device = rtl8251b_c45_match_phy_device, -- .name = "RTL8251B 5Gbps PHY", -- .get_features = rtl822x_get_features, -- .config_aneg = rtl822x_config_aneg, -- .read_status = rtl822x_read_status, -- .suspend = genphy_suspend, -- .resume = rtlgen_resume, -- .read_page = rtl821x_read_page, -- .write_page = rtl821x_write_page, -- }, { -- .match_phy_device = rtl_internal_nbaset_match_phy_device, -- .name = "Realtek Internal NBASE-T PHY", -- .flags = PHY_IS_INTERNAL, -- .get_features = rtl822x_get_features, -- .config_aneg = rtl822x_config_aneg, -- .read_status = rtl822x_read_status, -- .suspend = genphy_suspend, -- .resume = rtlgen_resume, -- .read_page = rtl821x_read_page, -- .write_page = rtl821x_write_page, -- .read_mmd = rtl822x_read_mmd, -- .write_mmd = rtl822x_write_mmd, -- }, { -- PHY_ID_MATCH_EXACT(0x001ccad0), -- .name = "RTL8224 2.5Gbps PHY", -- .get_features = rtl822x_c45_get_features, -- .config_aneg = rtl822x_c45_config_aneg, -- .read_status = rtl822x_c45_read_status, -- .suspend = genphy_c45_pma_suspend, -- .resume = rtlgen_c45_resume, -- }, { -- PHY_ID_MATCH_EXACT(0x001cc961), -- .name = "RTL8366RB Gigabit Ethernet", -- .config_init = &rtl8366rb_config_init, -- /* These interrupts are handled by the irq controller -- * embedded inside the RTL8366RB, they get unmasked when the -- * irq is requested and ACKed by reading the status register, -- * which is done by the irqchip code. -- */ -- .config_intr = genphy_no_config_intr, -- .handle_interrupt = genphy_handle_interrupt_no_ack, -- .suspend = genphy_suspend, -- .resume = genphy_resume, -- }, { -- PHY_ID_MATCH_EXACT(0x001ccb00), -- .name = "RTL9000AA_RTL9000AN Ethernet", -- .features = PHY_BASIC_T1_FEATURES, -- .config_init = rtl9000a_config_init, -- .config_aneg = rtl9000a_config_aneg, -- .read_status = rtl9000a_read_status, -- .config_intr = rtl9000a_config_intr, -- .handle_interrupt = rtl9000a_handle_interrupt, -- .suspend = genphy_suspend, -- .resume = genphy_resume, -- .read_page = rtl821x_read_page, -- .write_page = rtl821x_write_page, -- }, { -- PHY_ID_MATCH_EXACT(0x001cc942), -- .name = "RTL8365MB-VC Gigabit Ethernet", -- /* Interrupt handling analogous to RTL8366RB */ -- .config_intr = genphy_no_config_intr, -- .handle_interrupt = genphy_handle_interrupt_no_ack, -- .suspend = genphy_suspend, -- .resume = genphy_resume, -- }, { -- PHY_ID_MATCH_EXACT(0x001cc960), -- .name = "RTL8366S Gigabit Ethernet", -- .suspend = genphy_suspend, -- .resume = genphy_resume, -- .read_mmd = genphy_read_mmd_unsupported, -- .write_mmd = genphy_write_mmd_unsupported, -- }, --}; -- --module_phy_driver(realtek_drvs); -- --static const struct mdio_device_id __maybe_unused realtek_tbl[] = { -- { PHY_ID_MATCH_VENDOR(0x001cc800) }, -- { } --}; -- --MODULE_DEVICE_TABLE(mdio, realtek_tbl); ---- /dev/null -+++ b/drivers/net/phy/realtek/realtek_main.c -@@ -0,0 +1,1589 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* drivers/net/phy/realtek.c -+ * -+ * Driver for Realtek PHYs -+ * -+ * Author: Johnson Leung -+ * -+ * Copyright (c) 2004 Freescale Semiconductor, Inc. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define RTL821x_PHYSR 0x11 -+#define RTL821x_PHYSR_DUPLEX BIT(13) -+#define RTL821x_PHYSR_SPEED GENMASK(15, 14) -+ -+#define RTL821x_INER 0x12 -+#define RTL8211B_INER_INIT 0x6400 -+#define RTL8211E_INER_LINK_STATUS BIT(10) -+#define RTL8211F_INER_LINK_STATUS BIT(4) -+ -+#define RTL821x_INSR 0x13 -+ -+#define RTL821x_EXT_PAGE_SELECT 0x1e -+#define RTL821x_PAGE_SELECT 0x1f -+ -+#define RTL8211F_PHYCR1 0x18 -+#define RTL8211F_PHYCR2 0x19 -+#define RTL8211F_INSR 0x1d -+ -+#define RTL8211F_LEDCR 0x10 -+#define RTL8211F_LEDCR_MODE BIT(15) -+#define RTL8211F_LEDCR_ACT_TXRX BIT(4) -+#define RTL8211F_LEDCR_LINK_1000 BIT(3) -+#define RTL8211F_LEDCR_LINK_100 BIT(1) -+#define RTL8211F_LEDCR_LINK_10 BIT(0) -+#define RTL8211F_LEDCR_MASK GENMASK(4, 0) -+#define RTL8211F_LEDCR_SHIFT 5 -+ -+#define RTL8211F_TX_DELAY BIT(8) -+#define RTL8211F_RX_DELAY BIT(3) -+ -+#define RTL8211F_ALDPS_PLL_OFF BIT(1) -+#define RTL8211F_ALDPS_ENABLE BIT(2) -+#define RTL8211F_ALDPS_XTAL_OFF BIT(12) -+ -+#define RTL8211E_CTRL_DELAY BIT(13) -+#define RTL8211E_TX_DELAY BIT(12) -+#define RTL8211E_RX_DELAY BIT(11) -+ -+#define RTL8211F_CLKOUT_EN BIT(0) -+ -+#define RTL8201F_ISR 0x1e -+#define RTL8201F_ISR_ANERR BIT(15) -+#define RTL8201F_ISR_DUPLEX BIT(13) -+#define RTL8201F_ISR_LINK BIT(11) -+#define RTL8201F_ISR_MASK (RTL8201F_ISR_ANERR | \ -+ RTL8201F_ISR_DUPLEX | \ -+ RTL8201F_ISR_LINK) -+#define RTL8201F_IER 0x13 -+ -+#define RTL822X_VND1_SERDES_OPTION 0x697a -+#define RTL822X_VND1_SERDES_OPTION_MODE_MASK GENMASK(5, 0) -+#define RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII 0 -+#define RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX 2 -+ -+#define RTL822X_VND1_SERDES_CTRL3 0x7580 -+#define RTL822X_VND1_SERDES_CTRL3_MODE_MASK GENMASK(5, 0) -+#define RTL822X_VND1_SERDES_CTRL3_MODE_SGMII 0x02 -+#define RTL822X_VND1_SERDES_CTRL3_MODE_2500BASEX 0x16 -+ -+/* RTL822X_VND2_XXXXX registers are only accessible when phydev->is_c45 -+ * is set, they cannot be accessed by C45-over-C22. -+ */ -+#define RTL822X_VND2_GBCR 0xa412 -+ -+#define RTL822X_VND2_GANLPAR 0xa414 -+ -+#define RTL8366RB_POWER_SAVE 0x15 -+#define RTL8366RB_POWER_SAVE_ON BIT(12) -+ -+#define RTL9000A_GINMR 0x14 -+#define RTL9000A_GINMR_LINK_STATUS BIT(4) -+ -+#define RTL_VND2_PHYSR 0xa434 -+#define RTL_VND2_PHYSR_DUPLEX BIT(3) -+#define RTL_VND2_PHYSR_SPEEDL GENMASK(5, 4) -+#define RTL_VND2_PHYSR_SPEEDH GENMASK(10, 9) -+#define RTL_VND2_PHYSR_MASTER BIT(11) -+#define RTL_VND2_PHYSR_SPEED_MASK (RTL_VND2_PHYSR_SPEEDL | RTL_VND2_PHYSR_SPEEDH) -+ -+#define RTL_GENERIC_PHYID 0x001cc800 -+#define RTL_8211FVD_PHYID 0x001cc878 -+#define RTL_8221B 0x001cc840 -+#define RTL_8221B_VB_CG 0x001cc849 -+#define RTL_8221B_VN_CG 0x001cc84a -+#define RTL_8251B 0x001cc862 -+ -+#define RTL8211F_LED_COUNT 3 -+ -+MODULE_DESCRIPTION("Realtek PHY driver"); -+MODULE_AUTHOR("Johnson Leung"); -+MODULE_LICENSE("GPL"); -+ -+struct rtl821x_priv { -+ u16 phycr1; -+ u16 phycr2; -+ bool has_phycr2; -+ struct clk *clk; -+}; -+ -+static int rtl821x_read_page(struct phy_device *phydev) -+{ -+ return __phy_read(phydev, RTL821x_PAGE_SELECT); -+} -+ -+static int rtl821x_write_page(struct phy_device *phydev, int page) -+{ -+ return __phy_write(phydev, RTL821x_PAGE_SELECT, page); -+} -+ -+static int rtl821x_probe(struct phy_device *phydev) -+{ -+ struct device *dev = &phydev->mdio.dev; -+ struct rtl821x_priv *priv; -+ u32 phy_id = phydev->drv->phy_id; -+ int ret; -+ -+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ priv->clk = devm_clk_get_optional_enabled(dev, NULL); -+ if (IS_ERR(priv->clk)) -+ return dev_err_probe(dev, PTR_ERR(priv->clk), -+ "failed to get phy clock\n"); -+ -+ ret = phy_read_paged(phydev, 0xa43, RTL8211F_PHYCR1); -+ if (ret < 0) -+ return ret; -+ -+ priv->phycr1 = ret & (RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF); -+ if (of_property_read_bool(dev->of_node, "realtek,aldps-enable")) -+ priv->phycr1 |= RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF; -+ -+ priv->has_phycr2 = !(phy_id == RTL_8211FVD_PHYID); -+ if (priv->has_phycr2) { -+ ret = phy_read_paged(phydev, 0xa43, RTL8211F_PHYCR2); -+ if (ret < 0) -+ return ret; -+ -+ priv->phycr2 = ret & RTL8211F_CLKOUT_EN; -+ if (of_property_read_bool(dev->of_node, "realtek,clkout-disable")) -+ priv->phycr2 &= ~RTL8211F_CLKOUT_EN; -+ } -+ -+ phydev->priv = priv; -+ -+ return 0; -+} -+ -+static int rtl8201_ack_interrupt(struct phy_device *phydev) -+{ -+ int err; -+ -+ err = phy_read(phydev, RTL8201F_ISR); -+ -+ return (err < 0) ? err : 0; -+} -+ -+static int rtl821x_ack_interrupt(struct phy_device *phydev) -+{ -+ int err; -+ -+ err = phy_read(phydev, RTL821x_INSR); -+ -+ return (err < 0) ? err : 0; -+} -+ -+static int rtl8211f_ack_interrupt(struct phy_device *phydev) -+{ -+ int err; -+ -+ err = phy_read_paged(phydev, 0xa43, RTL8211F_INSR); -+ -+ return (err < 0) ? err : 0; -+} -+ -+static int rtl8201_config_intr(struct phy_device *phydev) -+{ -+ u16 val; -+ int err; -+ -+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { -+ err = rtl8201_ack_interrupt(phydev); -+ if (err) -+ return err; -+ -+ val = BIT(13) | BIT(12) | BIT(11); -+ err = phy_write_paged(phydev, 0x7, RTL8201F_IER, val); -+ } else { -+ val = 0; -+ err = phy_write_paged(phydev, 0x7, RTL8201F_IER, val); -+ if (err) -+ return err; -+ -+ err = rtl8201_ack_interrupt(phydev); -+ } -+ -+ return err; -+} -+ -+static int rtl8211b_config_intr(struct phy_device *phydev) -+{ -+ int err; -+ -+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { -+ err = rtl821x_ack_interrupt(phydev); -+ if (err) -+ return err; -+ -+ err = phy_write(phydev, RTL821x_INER, -+ RTL8211B_INER_INIT); -+ } else { -+ err = phy_write(phydev, RTL821x_INER, 0); -+ if (err) -+ return err; -+ -+ err = rtl821x_ack_interrupt(phydev); -+ } -+ -+ return err; -+} -+ -+static int rtl8211e_config_intr(struct phy_device *phydev) -+{ -+ int err; -+ -+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { -+ err = rtl821x_ack_interrupt(phydev); -+ if (err) -+ return err; -+ -+ err = phy_write(phydev, RTL821x_INER, -+ RTL8211E_INER_LINK_STATUS); -+ } else { -+ err = phy_write(phydev, RTL821x_INER, 0); -+ if (err) -+ return err; -+ -+ err = rtl821x_ack_interrupt(phydev); -+ } -+ -+ return err; -+} -+ -+static int rtl8211f_config_intr(struct phy_device *phydev) -+{ -+ u16 val; -+ int err; -+ -+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { -+ err = rtl8211f_ack_interrupt(phydev); -+ if (err) -+ return err; -+ -+ val = RTL8211F_INER_LINK_STATUS; -+ err = phy_write_paged(phydev, 0xa42, RTL821x_INER, val); -+ } else { -+ val = 0; -+ err = phy_write_paged(phydev, 0xa42, RTL821x_INER, val); -+ if (err) -+ return err; -+ -+ err = rtl8211f_ack_interrupt(phydev); -+ } -+ -+ return err; -+} -+ -+static irqreturn_t rtl8201_handle_interrupt(struct phy_device *phydev) -+{ -+ int irq_status; -+ -+ irq_status = phy_read(phydev, RTL8201F_ISR); -+ if (irq_status < 0) { -+ phy_error(phydev); -+ return IRQ_NONE; -+ } -+ -+ if (!(irq_status & RTL8201F_ISR_MASK)) -+ return IRQ_NONE; -+ -+ phy_trigger_machine(phydev); -+ -+ return IRQ_HANDLED; -+} -+ -+static irqreturn_t rtl821x_handle_interrupt(struct phy_device *phydev) -+{ -+ int irq_status, irq_enabled; -+ -+ irq_status = phy_read(phydev, RTL821x_INSR); -+ if (irq_status < 0) { -+ phy_error(phydev); -+ return IRQ_NONE; -+ } -+ -+ irq_enabled = phy_read(phydev, RTL821x_INER); -+ if (irq_enabled < 0) { -+ phy_error(phydev); -+ return IRQ_NONE; -+ } -+ -+ if (!(irq_status & irq_enabled)) -+ return IRQ_NONE; -+ -+ phy_trigger_machine(phydev); -+ -+ return IRQ_HANDLED; -+} -+ -+static irqreturn_t rtl8211f_handle_interrupt(struct phy_device *phydev) -+{ -+ int irq_status; -+ -+ irq_status = phy_read_paged(phydev, 0xa43, RTL8211F_INSR); -+ if (irq_status < 0) { -+ phy_error(phydev); -+ return IRQ_NONE; -+ } -+ -+ if (!(irq_status & RTL8211F_INER_LINK_STATUS)) -+ return IRQ_NONE; -+ -+ phy_trigger_machine(phydev); -+ -+ return IRQ_HANDLED; -+} -+ -+static int rtl8211_config_aneg(struct phy_device *phydev) -+{ -+ int ret; -+ -+ ret = genphy_config_aneg(phydev); -+ if (ret < 0) -+ return ret; -+ -+ /* Quirk was copied from vendor driver. Unfortunately it includes no -+ * description of the magic numbers. -+ */ -+ if (phydev->speed == SPEED_100 && phydev->autoneg == AUTONEG_DISABLE) { -+ phy_write(phydev, 0x17, 0x2138); -+ phy_write(phydev, 0x0e, 0x0260); -+ } else { -+ phy_write(phydev, 0x17, 0x2108); -+ phy_write(phydev, 0x0e, 0x0000); -+ } -+ -+ return 0; -+} -+ -+static int rtl8211c_config_init(struct phy_device *phydev) -+{ -+ /* RTL8211C has an issue when operating in Gigabit slave mode */ -+ return phy_set_bits(phydev, MII_CTRL1000, -+ CTL1000_ENABLE_MASTER | CTL1000_AS_MASTER); -+} -+ -+static int rtl8211f_config_init(struct phy_device *phydev) -+{ -+ struct rtl821x_priv *priv = phydev->priv; -+ struct device *dev = &phydev->mdio.dev; -+ u16 val_txdly, val_rxdly; -+ int ret; -+ -+ ret = phy_modify_paged_changed(phydev, 0xa43, RTL8211F_PHYCR1, -+ RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF, -+ priv->phycr1); -+ if (ret < 0) { -+ dev_err(dev, "aldps mode configuration failed: %pe\n", -+ ERR_PTR(ret)); -+ return ret; -+ } -+ -+ switch (phydev->interface) { -+ case PHY_INTERFACE_MODE_RGMII: -+ val_txdly = 0; -+ val_rxdly = 0; -+ break; -+ -+ case PHY_INTERFACE_MODE_RGMII_RXID: -+ val_txdly = 0; -+ val_rxdly = RTL8211F_RX_DELAY; -+ break; -+ -+ case PHY_INTERFACE_MODE_RGMII_TXID: -+ val_txdly = RTL8211F_TX_DELAY; -+ val_rxdly = 0; -+ break; -+ -+ case PHY_INTERFACE_MODE_RGMII_ID: -+ val_txdly = RTL8211F_TX_DELAY; -+ val_rxdly = RTL8211F_RX_DELAY; -+ break; -+ -+ default: /* the rest of the modes imply leaving delay as is. */ -+ return 0; -+ } -+ -+ ret = phy_modify_paged_changed(phydev, 0xd08, 0x11, RTL8211F_TX_DELAY, -+ val_txdly); -+ if (ret < 0) { -+ dev_err(dev, "Failed to update the TX delay register\n"); -+ return ret; -+ } else if (ret) { -+ dev_dbg(dev, -+ "%s 2ns TX delay (and changing the value from pin-strapping RXD1 or the bootloader)\n", -+ val_txdly ? "Enabling" : "Disabling"); -+ } else { -+ dev_dbg(dev, -+ "2ns TX delay was already %s (by pin-strapping RXD1 or bootloader configuration)\n", -+ val_txdly ? "enabled" : "disabled"); -+ } -+ -+ ret = phy_modify_paged_changed(phydev, 0xd08, 0x15, RTL8211F_RX_DELAY, -+ val_rxdly); -+ if (ret < 0) { -+ dev_err(dev, "Failed to update the RX delay register\n"); -+ return ret; -+ } else if (ret) { -+ dev_dbg(dev, -+ "%s 2ns RX delay (and changing the value from pin-strapping RXD0 or the bootloader)\n", -+ val_rxdly ? "Enabling" : "Disabling"); -+ } else { -+ dev_dbg(dev, -+ "2ns RX delay was already %s (by pin-strapping RXD0 or bootloader configuration)\n", -+ val_rxdly ? "enabled" : "disabled"); -+ } -+ -+ if (priv->has_phycr2) { -+ ret = phy_modify_paged(phydev, 0xa43, RTL8211F_PHYCR2, -+ RTL8211F_CLKOUT_EN, priv->phycr2); -+ if (ret < 0) { -+ dev_err(dev, "clkout configuration failed: %pe\n", -+ ERR_PTR(ret)); -+ return ret; -+ } -+ -+ return genphy_soft_reset(phydev); -+ } -+ -+ return 0; -+} -+ -+static int rtl821x_suspend(struct phy_device *phydev) -+{ -+ struct rtl821x_priv *priv = phydev->priv; -+ int ret = 0; -+ -+ if (!phydev->wol_enabled) { -+ ret = genphy_suspend(phydev); -+ -+ if (ret) -+ return ret; -+ -+ clk_disable_unprepare(priv->clk); -+ } -+ -+ return ret; -+} -+ -+static int rtl821x_resume(struct phy_device *phydev) -+{ -+ struct rtl821x_priv *priv = phydev->priv; -+ int ret; -+ -+ if (!phydev->wol_enabled) -+ clk_prepare_enable(priv->clk); -+ -+ ret = genphy_resume(phydev); -+ if (ret < 0) -+ return ret; -+ -+ msleep(20); -+ -+ return 0; -+} -+ -+static int rtl8211f_led_hw_is_supported(struct phy_device *phydev, u8 index, -+ unsigned long rules) -+{ -+ const unsigned long mask = BIT(TRIGGER_NETDEV_LINK_10) | -+ BIT(TRIGGER_NETDEV_LINK_100) | -+ BIT(TRIGGER_NETDEV_LINK_1000) | -+ BIT(TRIGGER_NETDEV_RX) | -+ BIT(TRIGGER_NETDEV_TX); -+ -+ /* The RTL8211F PHY supports these LED settings on up to three LEDs: -+ * - Link: Configurable subset of 10/100/1000 link rates -+ * - Active: Blink on activity, RX or TX is not differentiated -+ * The Active option has two modes, A and B: -+ * - A: Link and Active indication at configurable, but matching, -+ * subset of 10/100/1000 link rates -+ * - B: Link indication at configurable subset of 10/100/1000 link -+ * rates and Active indication always at all three 10+100+1000 -+ * link rates. -+ * This code currently uses mode B only. -+ */ -+ -+ if (index >= RTL8211F_LED_COUNT) -+ return -EINVAL; -+ -+ /* Filter out any other unsupported triggers. */ -+ if (rules & ~mask) -+ return -EOPNOTSUPP; -+ -+ /* RX and TX are not differentiated, either both are set or not set. */ -+ if (!(rules & BIT(TRIGGER_NETDEV_RX)) ^ !(rules & BIT(TRIGGER_NETDEV_TX))) -+ return -EOPNOTSUPP; -+ -+ return 0; -+} -+ -+static int rtl8211f_led_hw_control_get(struct phy_device *phydev, u8 index, -+ unsigned long *rules) -+{ -+ int val; -+ -+ if (index >= RTL8211F_LED_COUNT) -+ return -EINVAL; -+ -+ val = phy_read_paged(phydev, 0xd04, RTL8211F_LEDCR); -+ if (val < 0) -+ return val; -+ -+ val >>= RTL8211F_LEDCR_SHIFT * index; -+ val &= RTL8211F_LEDCR_MASK; -+ -+ if (val & RTL8211F_LEDCR_LINK_10) -+ set_bit(TRIGGER_NETDEV_LINK_10, rules); -+ -+ if (val & RTL8211F_LEDCR_LINK_100) -+ set_bit(TRIGGER_NETDEV_LINK_100, rules); -+ -+ if (val & RTL8211F_LEDCR_LINK_1000) -+ set_bit(TRIGGER_NETDEV_LINK_1000, rules); -+ -+ if (val & RTL8211F_LEDCR_ACT_TXRX) { -+ set_bit(TRIGGER_NETDEV_RX, rules); -+ set_bit(TRIGGER_NETDEV_TX, rules); -+ } -+ -+ return 0; -+} -+ -+static int rtl8211f_led_hw_control_set(struct phy_device *phydev, u8 index, -+ unsigned long rules) -+{ -+ const u16 mask = RTL8211F_LEDCR_MASK << (RTL8211F_LEDCR_SHIFT * index); -+ u16 reg = 0; -+ -+ if (index >= RTL8211F_LED_COUNT) -+ return -EINVAL; -+ -+ if (test_bit(TRIGGER_NETDEV_LINK_10, &rules)) -+ reg |= RTL8211F_LEDCR_LINK_10; -+ -+ if (test_bit(TRIGGER_NETDEV_LINK_100, &rules)) -+ reg |= RTL8211F_LEDCR_LINK_100; -+ -+ if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules)) -+ reg |= RTL8211F_LEDCR_LINK_1000; -+ -+ if (test_bit(TRIGGER_NETDEV_RX, &rules) || -+ test_bit(TRIGGER_NETDEV_TX, &rules)) { -+ reg |= RTL8211F_LEDCR_ACT_TXRX; -+ } -+ -+ reg <<= RTL8211F_LEDCR_SHIFT * index; -+ reg |= RTL8211F_LEDCR_MODE; /* Mode B */ -+ -+ return phy_modify_paged(phydev, 0xd04, RTL8211F_LEDCR, mask, reg); -+} -+ -+static int rtl8211e_config_init(struct phy_device *phydev) -+{ -+ int ret = 0, oldpage; -+ u16 val; -+ -+ /* enable TX/RX delay for rgmii-* modes, and disable them for rgmii. */ -+ switch (phydev->interface) { -+ case PHY_INTERFACE_MODE_RGMII: -+ val = RTL8211E_CTRL_DELAY | 0; -+ break; -+ case PHY_INTERFACE_MODE_RGMII_ID: -+ val = RTL8211E_CTRL_DELAY | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY; -+ break; -+ case PHY_INTERFACE_MODE_RGMII_RXID: -+ val = RTL8211E_CTRL_DELAY | RTL8211E_RX_DELAY; -+ break; -+ case PHY_INTERFACE_MODE_RGMII_TXID: -+ val = RTL8211E_CTRL_DELAY | RTL8211E_TX_DELAY; -+ break; -+ default: /* the rest of the modes imply leaving delays as is. */ -+ return 0; -+ } -+ -+ /* According to a sample driver there is a 0x1c config register on the -+ * 0xa4 extension page (0x7) layout. It can be used to disable/enable -+ * the RX/TX delays otherwise controlled by RXDLY/TXDLY pins. -+ * The configuration register definition: -+ * 14 = reserved -+ * 13 = Force Tx RX Delay controlled by bit12 bit11, -+ * 12 = RX Delay, 11 = TX Delay -+ * 10:0 = Test && debug settings reserved by realtek -+ */ -+ oldpage = phy_select_page(phydev, 0x7); -+ if (oldpage < 0) -+ goto err_restore_page; -+ -+ ret = __phy_write(phydev, RTL821x_EXT_PAGE_SELECT, 0xa4); -+ if (ret) -+ goto err_restore_page; -+ -+ ret = __phy_modify(phydev, 0x1c, RTL8211E_CTRL_DELAY -+ | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY, -+ val); -+ -+err_restore_page: -+ return phy_restore_page(phydev, oldpage, ret); -+} -+ -+static int rtl8211b_suspend(struct phy_device *phydev) -+{ -+ phy_write(phydev, MII_MMD_DATA, BIT(9)); -+ -+ return genphy_suspend(phydev); -+} -+ -+static int rtl8211b_resume(struct phy_device *phydev) -+{ -+ phy_write(phydev, MII_MMD_DATA, 0); -+ -+ return genphy_resume(phydev); -+} -+ -+static int rtl8366rb_config_init(struct phy_device *phydev) -+{ -+ int ret; -+ -+ ret = phy_set_bits(phydev, RTL8366RB_POWER_SAVE, -+ RTL8366RB_POWER_SAVE_ON); -+ if (ret) { -+ dev_err(&phydev->mdio.dev, -+ "error enabling power management\n"); -+ } -+ -+ return ret; -+} -+ -+/* get actual speed to cover the downshift case */ -+static void rtlgen_decode_physr(struct phy_device *phydev, int val) -+{ -+ /* bit 3 -+ * 0: Half Duplex -+ * 1: Full Duplex -+ */ -+ if (val & RTL_VND2_PHYSR_DUPLEX) -+ phydev->duplex = DUPLEX_FULL; -+ else -+ phydev->duplex = DUPLEX_HALF; -+ -+ switch (val & RTL_VND2_PHYSR_SPEED_MASK) { -+ case 0x0000: -+ phydev->speed = SPEED_10; -+ break; -+ case 0x0010: -+ phydev->speed = SPEED_100; -+ break; -+ case 0x0020: -+ phydev->speed = SPEED_1000; -+ break; -+ case 0x0200: -+ phydev->speed = SPEED_10000; -+ break; -+ case 0x0210: -+ phydev->speed = SPEED_2500; -+ break; -+ case 0x0220: -+ phydev->speed = SPEED_5000; -+ break; -+ default: -+ break; -+ } -+ -+ /* bit 11 -+ * 0: Slave Mode -+ * 1: Master Mode -+ */ -+ if (phydev->speed >= 1000) { -+ if (val & RTL_VND2_PHYSR_MASTER) -+ phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER; -+ else -+ phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE; -+ } else { -+ phydev->master_slave_state = MASTER_SLAVE_STATE_UNSUPPORTED; -+ } -+} -+ -+static int rtlgen_read_status(struct phy_device *phydev) -+{ -+ int ret, val; -+ -+ ret = genphy_read_status(phydev); -+ if (ret < 0) -+ return ret; -+ -+ if (!phydev->link) -+ return 0; -+ -+ val = phy_read_paged(phydev, 0xa43, 0x12); -+ if (val < 0) -+ return val; -+ -+ rtlgen_decode_physr(phydev, val); -+ -+ return 0; -+} -+ -+static int rtlgen_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) -+{ -+ int ret; -+ -+ if (devnum == MDIO_MMD_VEND2) { -+ rtl821x_write_page(phydev, regnum >> 4); -+ ret = __phy_read(phydev, 0x10 + ((regnum & 0xf) >> 1)); -+ rtl821x_write_page(phydev, 0); -+ } else if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) { -+ rtl821x_write_page(phydev, 0xa5c); -+ ret = __phy_read(phydev, 0x12); -+ rtl821x_write_page(phydev, 0); -+ } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) { -+ rtl821x_write_page(phydev, 0xa5d); -+ ret = __phy_read(phydev, 0x10); -+ rtl821x_write_page(phydev, 0); -+ } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE) { -+ rtl821x_write_page(phydev, 0xa5d); -+ ret = __phy_read(phydev, 0x11); -+ rtl821x_write_page(phydev, 0); -+ } else { -+ ret = -EOPNOTSUPP; -+ } -+ -+ return ret; -+} -+ -+static int rtlgen_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, -+ u16 val) -+{ -+ int ret; -+ -+ if (devnum == MDIO_MMD_VEND2) { -+ rtl821x_write_page(phydev, regnum >> 4); -+ ret = __phy_write(phydev, 0x10 + ((regnum & 0xf) >> 1), val); -+ rtl821x_write_page(phydev, 0); -+ } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) { -+ rtl821x_write_page(phydev, 0xa5d); -+ ret = __phy_write(phydev, 0x10, val); -+ rtl821x_write_page(phydev, 0); -+ } else { -+ ret = -EOPNOTSUPP; -+ } -+ -+ return ret; -+} -+ -+static int rtl822x_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) -+{ -+ int ret = rtlgen_read_mmd(phydev, devnum, regnum); -+ -+ if (ret != -EOPNOTSUPP) -+ return ret; -+ -+ if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE2) { -+ rtl821x_write_page(phydev, 0xa6e); -+ ret = __phy_read(phydev, 0x16); -+ rtl821x_write_page(phydev, 0); -+ } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) { -+ rtl821x_write_page(phydev, 0xa6d); -+ ret = __phy_read(phydev, 0x12); -+ rtl821x_write_page(phydev, 0); -+ } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE2) { -+ rtl821x_write_page(phydev, 0xa6d); -+ ret = __phy_read(phydev, 0x10); -+ rtl821x_write_page(phydev, 0); -+ } -+ -+ return ret; -+} -+ -+static int rtl822x_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, -+ u16 val) -+{ -+ int ret = rtlgen_write_mmd(phydev, devnum, regnum, val); -+ -+ if (ret != -EOPNOTSUPP) -+ return ret; -+ -+ if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) { -+ rtl821x_write_page(phydev, 0xa6d); -+ ret = __phy_write(phydev, 0x12, val); -+ rtl821x_write_page(phydev, 0); -+ } -+ -+ return ret; -+} -+ -+static int rtl822xb_config_init(struct phy_device *phydev) -+{ -+ bool has_2500, has_sgmii; -+ u16 mode; -+ int ret; -+ -+ has_2500 = test_bit(PHY_INTERFACE_MODE_2500BASEX, -+ phydev->host_interfaces) || -+ phydev->interface == PHY_INTERFACE_MODE_2500BASEX; -+ -+ has_sgmii = test_bit(PHY_INTERFACE_MODE_SGMII, -+ phydev->host_interfaces) || -+ phydev->interface == PHY_INTERFACE_MODE_SGMII; -+ -+ /* fill in possible interfaces */ -+ __assign_bit(PHY_INTERFACE_MODE_2500BASEX, phydev->possible_interfaces, -+ has_2500); -+ __assign_bit(PHY_INTERFACE_MODE_SGMII, phydev->possible_interfaces, -+ has_sgmii); -+ -+ if (!has_2500 && !has_sgmii) -+ return 0; -+ -+ /* determine SerDes option mode */ -+ if (has_2500 && !has_sgmii) { -+ mode = RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX; -+ phydev->rate_matching = RATE_MATCH_PAUSE; -+ } else { -+ mode = RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII; -+ phydev->rate_matching = RATE_MATCH_NONE; -+ } -+ -+ /* the following sequence with magic numbers sets up the SerDes -+ * option mode -+ */ -+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x75f3, 0); -+ if (ret < 0) -+ return ret; -+ -+ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND1, -+ RTL822X_VND1_SERDES_OPTION, -+ RTL822X_VND1_SERDES_OPTION_MODE_MASK, -+ mode); -+ if (ret < 0) -+ return ret; -+ -+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6a04, 0x0503); -+ if (ret < 0) -+ return ret; -+ -+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f10, 0xd455); -+ if (ret < 0) -+ return ret; -+ -+ return phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f11, 0x8020); -+} -+ -+static int rtl822xb_get_rate_matching(struct phy_device *phydev, -+ phy_interface_t iface) -+{ -+ int val; -+ -+ /* Only rate matching at 2500base-x */ -+ if (iface != PHY_INTERFACE_MODE_2500BASEX) -+ return RATE_MATCH_NONE; -+ -+ val = phy_read_mmd(phydev, MDIO_MMD_VEND1, RTL822X_VND1_SERDES_OPTION); -+ if (val < 0) -+ return val; -+ -+ if ((val & RTL822X_VND1_SERDES_OPTION_MODE_MASK) == -+ RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX) -+ return RATE_MATCH_PAUSE; -+ -+ /* RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII */ -+ return RATE_MATCH_NONE; -+} -+ -+static int rtl822x_get_features(struct phy_device *phydev) -+{ -+ int val; -+ -+ val = phy_read_paged(phydev, 0xa61, 0x13); -+ if (val < 0) -+ return val; -+ -+ linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, -+ phydev->supported, val & MDIO_PMA_SPEED_2_5G); -+ linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, -+ phydev->supported, val & MDIO_PMA_SPEED_5G); -+ linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, -+ phydev->supported, val & MDIO_SPEED_10G); -+ -+ return genphy_read_abilities(phydev); -+} -+ -+static int rtl822x_config_aneg(struct phy_device *phydev) -+{ -+ int ret = 0; -+ -+ if (phydev->autoneg == AUTONEG_ENABLE) { -+ u16 adv = linkmode_adv_to_mii_10gbt_adv_t(phydev->advertising); -+ -+ ret = phy_modify_paged_changed(phydev, 0xa5d, 0x12, -+ MDIO_AN_10GBT_CTRL_ADV2_5G | -+ MDIO_AN_10GBT_CTRL_ADV5G, -+ adv); -+ if (ret < 0) -+ return ret; -+ } -+ -+ return __genphy_config_aneg(phydev, ret); -+} -+ -+static void rtl822xb_update_interface(struct phy_device *phydev) -+{ -+ int val; -+ -+ if (!phydev->link) -+ return; -+ -+ /* Change interface according to serdes mode */ -+ val = phy_read_mmd(phydev, MDIO_MMD_VEND1, RTL822X_VND1_SERDES_CTRL3); -+ if (val < 0) -+ return; -+ -+ switch (val & RTL822X_VND1_SERDES_CTRL3_MODE_MASK) { -+ case RTL822X_VND1_SERDES_CTRL3_MODE_2500BASEX: -+ phydev->interface = PHY_INTERFACE_MODE_2500BASEX; -+ break; -+ case RTL822X_VND1_SERDES_CTRL3_MODE_SGMII: -+ phydev->interface = PHY_INTERFACE_MODE_SGMII; -+ break; -+ } -+} -+ -+static int rtl822x_read_status(struct phy_device *phydev) -+{ -+ int lpadv, ret; -+ -+ mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, 0); -+ -+ ret = rtlgen_read_status(phydev); -+ if (ret < 0) -+ return ret; -+ -+ if (phydev->autoneg == AUTONEG_DISABLE || -+ !phydev->autoneg_complete) -+ return 0; -+ -+ lpadv = phy_read_paged(phydev, 0xa5d, 0x13); -+ if (lpadv < 0) -+ return lpadv; -+ -+ mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, lpadv); -+ -+ return 0; -+} -+ -+static int rtl822xb_read_status(struct phy_device *phydev) -+{ -+ int ret; -+ -+ ret = rtl822x_read_status(phydev); -+ if (ret < 0) -+ return ret; -+ -+ rtl822xb_update_interface(phydev); -+ -+ return 0; -+} -+ -+static int rtl822x_c45_get_features(struct phy_device *phydev) -+{ -+ linkmode_set_bit(ETHTOOL_LINK_MODE_TP_BIT, -+ phydev->supported); -+ -+ return genphy_c45_pma_read_abilities(phydev); -+} -+ -+static int rtl822x_c45_config_aneg(struct phy_device *phydev) -+{ -+ bool changed = false; -+ int ret, val; -+ -+ if (phydev->autoneg == AUTONEG_DISABLE) -+ return genphy_c45_pma_setup_forced(phydev); -+ -+ ret = genphy_c45_an_config_aneg(phydev); -+ if (ret < 0) -+ return ret; -+ if (ret > 0) -+ changed = true; -+ -+ val = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising); -+ -+ /* Vendor register as C45 has no standardized support for 1000BaseT */ -+ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, RTL822X_VND2_GBCR, -+ ADVERTISE_1000FULL, val); -+ if (ret < 0) -+ return ret; -+ if (ret > 0) -+ changed = true; -+ -+ return genphy_c45_check_and_restart_aneg(phydev, changed); -+} -+ -+static int rtl822x_c45_read_status(struct phy_device *phydev) -+{ -+ int ret, val; -+ -+ /* Vendor register as C45 has no standardized support for 1000BaseT */ -+ if (phydev->autoneg == AUTONEG_ENABLE && genphy_c45_aneg_done(phydev)) { -+ val = phy_read_mmd(phydev, MDIO_MMD_VEND2, -+ RTL822X_VND2_GANLPAR); -+ if (val < 0) -+ return val; -+ } else { -+ val = 0; -+ } -+ mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, val); -+ -+ ret = genphy_c45_read_status(phydev); -+ if (ret < 0) -+ return ret; -+ -+ if (!phydev->link) { -+ phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN; -+ return 0; -+ } -+ -+ /* Read actual speed from vendor register. */ -+ val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL_VND2_PHYSR); -+ if (val < 0) -+ return val; -+ -+ rtlgen_decode_physr(phydev, val); -+ -+ return 0; -+} -+ -+static int rtl822xb_c45_read_status(struct phy_device *phydev) -+{ -+ int ret; -+ -+ ret = rtl822x_c45_read_status(phydev); -+ if (ret < 0) -+ return ret; -+ -+ rtl822xb_update_interface(phydev); -+ -+ return 0; -+} -+ -+static bool rtlgen_supports_2_5gbps(struct phy_device *phydev) -+{ -+ int val; -+ -+ phy_write(phydev, RTL821x_PAGE_SELECT, 0xa61); -+ val = phy_read(phydev, 0x13); -+ phy_write(phydev, RTL821x_PAGE_SELECT, 0); -+ -+ return val >= 0 && val & MDIO_PMA_SPEED_2_5G; -+} -+ -+/* On internal PHY's MMD reads over C22 always return 0. -+ * Check a MMD register which is known to be non-zero. -+ */ -+static bool rtlgen_supports_mmd(struct phy_device *phydev) -+{ -+ int val; -+ -+ phy_lock_mdio_bus(phydev); -+ __phy_write(phydev, MII_MMD_CTRL, MDIO_MMD_PCS); -+ __phy_write(phydev, MII_MMD_DATA, MDIO_PCS_EEE_ABLE); -+ __phy_write(phydev, MII_MMD_CTRL, MDIO_MMD_PCS | MII_MMD_CTRL_NOINCR); -+ val = __phy_read(phydev, MII_MMD_DATA); -+ phy_unlock_mdio_bus(phydev); -+ -+ return val > 0; -+} -+ -+static int rtlgen_match_phy_device(struct phy_device *phydev) -+{ -+ return phydev->phy_id == RTL_GENERIC_PHYID && -+ !rtlgen_supports_2_5gbps(phydev); -+} -+ -+static int rtl8226_match_phy_device(struct phy_device *phydev) -+{ -+ return phydev->phy_id == RTL_GENERIC_PHYID && -+ rtlgen_supports_2_5gbps(phydev) && -+ rtlgen_supports_mmd(phydev); -+} -+ -+static int rtlgen_is_c45_match(struct phy_device *phydev, unsigned int id, -+ bool is_c45) -+{ -+ if (phydev->is_c45) -+ return is_c45 && (id == phydev->c45_ids.device_ids[1]); -+ else -+ return !is_c45 && (id == phydev->phy_id); -+} -+ -+static int rtl8221b_match_phy_device(struct phy_device *phydev) -+{ -+ return phydev->phy_id == RTL_8221B && rtlgen_supports_mmd(phydev); -+} -+ -+static int rtl8221b_vb_cg_c22_match_phy_device(struct phy_device *phydev) -+{ -+ return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, false); -+} -+ -+static int rtl8221b_vb_cg_c45_match_phy_device(struct phy_device *phydev) -+{ -+ return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, true); -+} -+ -+static int rtl8221b_vn_cg_c22_match_phy_device(struct phy_device *phydev) -+{ -+ return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, false); -+} -+ -+static int rtl8221b_vn_cg_c45_match_phy_device(struct phy_device *phydev) -+{ -+ return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, true); -+} -+ -+static int rtl_internal_nbaset_match_phy_device(struct phy_device *phydev) -+{ -+ if (phydev->is_c45) -+ return false; -+ -+ switch (phydev->phy_id) { -+ case RTL_GENERIC_PHYID: -+ case RTL_8221B: -+ case RTL_8251B: -+ case 0x001cc841: -+ break; -+ default: -+ return false; -+ } -+ -+ return rtlgen_supports_2_5gbps(phydev) && !rtlgen_supports_mmd(phydev); -+} -+ -+static int rtl8251b_c45_match_phy_device(struct phy_device *phydev) -+{ -+ return rtlgen_is_c45_match(phydev, RTL_8251B, true); -+} -+ -+static int rtlgen_resume(struct phy_device *phydev) -+{ -+ int ret = genphy_resume(phydev); -+ -+ /* Internal PHY's from RTL8168h up may not be instantly ready */ -+ msleep(20); -+ -+ return ret; -+} -+ -+static int rtlgen_c45_resume(struct phy_device *phydev) -+{ -+ int ret = genphy_c45_pma_resume(phydev); -+ -+ msleep(20); -+ -+ return ret; -+} -+ -+static int rtl9000a_config_init(struct phy_device *phydev) -+{ -+ phydev->autoneg = AUTONEG_DISABLE; -+ phydev->speed = SPEED_100; -+ phydev->duplex = DUPLEX_FULL; -+ -+ return 0; -+} -+ -+static int rtl9000a_config_aneg(struct phy_device *phydev) -+{ -+ int ret; -+ u16 ctl = 0; -+ -+ switch (phydev->master_slave_set) { -+ case MASTER_SLAVE_CFG_MASTER_FORCE: -+ ctl |= CTL1000_AS_MASTER; -+ break; -+ case MASTER_SLAVE_CFG_SLAVE_FORCE: -+ break; -+ case MASTER_SLAVE_CFG_UNKNOWN: -+ case MASTER_SLAVE_CFG_UNSUPPORTED: -+ return 0; -+ default: -+ phydev_warn(phydev, "Unsupported Master/Slave mode\n"); -+ return -EOPNOTSUPP; -+ } -+ -+ ret = phy_modify_changed(phydev, MII_CTRL1000, CTL1000_AS_MASTER, ctl); -+ if (ret == 1) -+ ret = genphy_soft_reset(phydev); -+ -+ return ret; -+} -+ -+static int rtl9000a_read_status(struct phy_device *phydev) -+{ -+ int ret; -+ -+ phydev->master_slave_get = MASTER_SLAVE_CFG_UNKNOWN; -+ phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN; -+ -+ ret = genphy_update_link(phydev); -+ if (ret) -+ return ret; -+ -+ ret = phy_read(phydev, MII_CTRL1000); -+ if (ret < 0) -+ return ret; -+ if (ret & CTL1000_AS_MASTER) -+ phydev->master_slave_get = MASTER_SLAVE_CFG_MASTER_FORCE; -+ else -+ phydev->master_slave_get = MASTER_SLAVE_CFG_SLAVE_FORCE; -+ -+ ret = phy_read(phydev, MII_STAT1000); -+ if (ret < 0) -+ return ret; -+ if (ret & LPA_1000MSRES) -+ phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER; -+ else -+ phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE; -+ -+ return 0; -+} -+ -+static int rtl9000a_ack_interrupt(struct phy_device *phydev) -+{ -+ int err; -+ -+ err = phy_read(phydev, RTL8211F_INSR); -+ -+ return (err < 0) ? err : 0; -+} -+ -+static int rtl9000a_config_intr(struct phy_device *phydev) -+{ -+ u16 val; -+ int err; -+ -+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { -+ err = rtl9000a_ack_interrupt(phydev); -+ if (err) -+ return err; -+ -+ val = (u16)~RTL9000A_GINMR_LINK_STATUS; -+ err = phy_write_paged(phydev, 0xa42, RTL9000A_GINMR, val); -+ } else { -+ val = ~0; -+ err = phy_write_paged(phydev, 0xa42, RTL9000A_GINMR, val); -+ if (err) -+ return err; -+ -+ err = rtl9000a_ack_interrupt(phydev); -+ } -+ -+ return phy_write_paged(phydev, 0xa42, RTL9000A_GINMR, val); -+} -+ -+static irqreturn_t rtl9000a_handle_interrupt(struct phy_device *phydev) -+{ -+ int irq_status; -+ -+ irq_status = phy_read(phydev, RTL8211F_INSR); -+ if (irq_status < 0) { -+ phy_error(phydev); -+ return IRQ_NONE; -+ } -+ -+ if (!(irq_status & RTL8211F_INER_LINK_STATUS)) -+ return IRQ_NONE; -+ -+ phy_trigger_machine(phydev); -+ -+ return IRQ_HANDLED; -+} -+ -+static struct phy_driver realtek_drvs[] = { -+ { -+ PHY_ID_MATCH_EXACT(0x00008201), -+ .name = "RTL8201CP Ethernet", -+ .read_page = rtl821x_read_page, -+ .write_page = rtl821x_write_page, -+ }, { -+ PHY_ID_MATCH_EXACT(0x001cc816), -+ .name = "RTL8201F Fast Ethernet", -+ .config_intr = &rtl8201_config_intr, -+ .handle_interrupt = rtl8201_handle_interrupt, -+ .suspend = genphy_suspend, -+ .resume = genphy_resume, -+ .read_page = rtl821x_read_page, -+ .write_page = rtl821x_write_page, -+ }, { -+ PHY_ID_MATCH_MODEL(0x001cc880), -+ .name = "RTL8208 Fast Ethernet", -+ .read_mmd = genphy_read_mmd_unsupported, -+ .write_mmd = genphy_write_mmd_unsupported, -+ .suspend = genphy_suspend, -+ .resume = genphy_resume, -+ .read_page = rtl821x_read_page, -+ .write_page = rtl821x_write_page, -+ }, { -+ PHY_ID_MATCH_EXACT(0x001cc910), -+ .name = "RTL8211 Gigabit Ethernet", -+ .config_aneg = rtl8211_config_aneg, -+ .read_mmd = &genphy_read_mmd_unsupported, -+ .write_mmd = &genphy_write_mmd_unsupported, -+ .read_page = rtl821x_read_page, -+ .write_page = rtl821x_write_page, -+ }, { -+ PHY_ID_MATCH_EXACT(0x001cc912), -+ .name = "RTL8211B Gigabit Ethernet", -+ .config_intr = &rtl8211b_config_intr, -+ .handle_interrupt = rtl821x_handle_interrupt, -+ .read_mmd = &genphy_read_mmd_unsupported, -+ .write_mmd = &genphy_write_mmd_unsupported, -+ .suspend = rtl8211b_suspend, -+ .resume = rtl8211b_resume, -+ .read_page = rtl821x_read_page, -+ .write_page = rtl821x_write_page, -+ }, { -+ PHY_ID_MATCH_EXACT(0x001cc913), -+ .name = "RTL8211C Gigabit Ethernet", -+ .config_init = rtl8211c_config_init, -+ .read_mmd = &genphy_read_mmd_unsupported, -+ .write_mmd = &genphy_write_mmd_unsupported, -+ .read_page = rtl821x_read_page, -+ .write_page = rtl821x_write_page, -+ }, { -+ PHY_ID_MATCH_EXACT(0x001cc914), -+ .name = "RTL8211DN Gigabit Ethernet", -+ .config_intr = rtl8211e_config_intr, -+ .handle_interrupt = rtl821x_handle_interrupt, -+ .suspend = genphy_suspend, -+ .resume = genphy_resume, -+ .read_page = rtl821x_read_page, -+ .write_page = rtl821x_write_page, -+ }, { -+ PHY_ID_MATCH_EXACT(0x001cc915), -+ .name = "RTL8211E Gigabit Ethernet", -+ .config_init = &rtl8211e_config_init, -+ .config_intr = &rtl8211e_config_intr, -+ .handle_interrupt = rtl821x_handle_interrupt, -+ .suspend = genphy_suspend, -+ .resume = genphy_resume, -+ .read_page = rtl821x_read_page, -+ .write_page = rtl821x_write_page, -+ }, { -+ PHY_ID_MATCH_EXACT(0x001cc916), -+ .name = "RTL8211F Gigabit Ethernet", -+ .probe = rtl821x_probe, -+ .config_init = &rtl8211f_config_init, -+ .read_status = rtlgen_read_status, -+ .config_intr = &rtl8211f_config_intr, -+ .handle_interrupt = rtl8211f_handle_interrupt, -+ .suspend = rtl821x_suspend, -+ .resume = rtl821x_resume, -+ .read_page = rtl821x_read_page, -+ .write_page = rtl821x_write_page, -+ .flags = PHY_ALWAYS_CALL_SUSPEND, -+ .led_hw_is_supported = rtl8211f_led_hw_is_supported, -+ .led_hw_control_get = rtl8211f_led_hw_control_get, -+ .led_hw_control_set = rtl8211f_led_hw_control_set, -+ }, { -+ PHY_ID_MATCH_EXACT(RTL_8211FVD_PHYID), -+ .name = "RTL8211F-VD Gigabit Ethernet", -+ .probe = rtl821x_probe, -+ .config_init = &rtl8211f_config_init, -+ .read_status = rtlgen_read_status, -+ .config_intr = &rtl8211f_config_intr, -+ .handle_interrupt = rtl8211f_handle_interrupt, -+ .suspend = rtl821x_suspend, -+ .resume = rtl821x_resume, -+ .read_page = rtl821x_read_page, -+ .write_page = rtl821x_write_page, -+ .flags = PHY_ALWAYS_CALL_SUSPEND, -+ }, { -+ .name = "Generic FE-GE Realtek PHY", -+ .match_phy_device = rtlgen_match_phy_device, -+ .read_status = rtlgen_read_status, -+ .suspend = genphy_suspend, -+ .resume = rtlgen_resume, -+ .read_page = rtl821x_read_page, -+ .write_page = rtl821x_write_page, -+ .read_mmd = rtlgen_read_mmd, -+ .write_mmd = rtlgen_write_mmd, -+ }, { -+ .name = "RTL8226 2.5Gbps PHY", -+ .match_phy_device = rtl8226_match_phy_device, -+ .get_features = rtl822x_get_features, -+ .config_aneg = rtl822x_config_aneg, -+ .read_status = rtl822x_read_status, -+ .suspend = genphy_suspend, -+ .resume = rtlgen_resume, -+ .read_page = rtl821x_read_page, -+ .write_page = rtl821x_write_page, -+ }, { -+ .match_phy_device = rtl8221b_match_phy_device, -+ .name = "RTL8226B_RTL8221B 2.5Gbps PHY", -+ .get_features = rtl822x_get_features, -+ .config_aneg = rtl822x_config_aneg, -+ .config_init = rtl822xb_config_init, -+ .get_rate_matching = rtl822xb_get_rate_matching, -+ .read_status = rtl822xb_read_status, -+ .suspend = genphy_suspend, -+ .resume = rtlgen_resume, -+ .read_page = rtl821x_read_page, -+ .write_page = rtl821x_write_page, -+ }, { -+ PHY_ID_MATCH_EXACT(0x001cc838), -+ .name = "RTL8226-CG 2.5Gbps PHY", -+ .get_features = rtl822x_get_features, -+ .config_aneg = rtl822x_config_aneg, -+ .read_status = rtl822x_read_status, -+ .suspend = genphy_suspend, -+ .resume = rtlgen_resume, -+ .read_page = rtl821x_read_page, -+ .write_page = rtl821x_write_page, -+ }, { -+ PHY_ID_MATCH_EXACT(0x001cc848), -+ .name = "RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY", -+ .get_features = rtl822x_get_features, -+ .config_aneg = rtl822x_config_aneg, -+ .config_init = rtl822xb_config_init, -+ .get_rate_matching = rtl822xb_get_rate_matching, -+ .read_status = rtl822xb_read_status, -+ .suspend = genphy_suspend, -+ .resume = rtlgen_resume, -+ .read_page = rtl821x_read_page, -+ .write_page = rtl821x_write_page, -+ }, { -+ .match_phy_device = rtl8221b_vb_cg_c22_match_phy_device, -+ .name = "RTL8221B-VB-CG 2.5Gbps PHY (C22)", -+ .get_features = rtl822x_get_features, -+ .config_aneg = rtl822x_config_aneg, -+ .config_init = rtl822xb_config_init, -+ .get_rate_matching = rtl822xb_get_rate_matching, -+ .read_status = rtl822xb_read_status, -+ .suspend = genphy_suspend, -+ .resume = rtlgen_resume, -+ .read_page = rtl821x_read_page, -+ .write_page = rtl821x_write_page, -+ }, { -+ .match_phy_device = rtl8221b_vb_cg_c45_match_phy_device, -+ .name = "RTL8221B-VB-CG 2.5Gbps PHY (C45)", -+ .config_init = rtl822xb_config_init, -+ .get_rate_matching = rtl822xb_get_rate_matching, -+ .get_features = rtl822x_c45_get_features, -+ .config_aneg = rtl822x_c45_config_aneg, -+ .read_status = rtl822xb_c45_read_status, -+ .suspend = genphy_c45_pma_suspend, -+ .resume = rtlgen_c45_resume, -+ }, { -+ .match_phy_device = rtl8221b_vn_cg_c22_match_phy_device, -+ .name = "RTL8221B-VM-CG 2.5Gbps PHY (C22)", -+ .get_features = rtl822x_get_features, -+ .config_aneg = rtl822x_config_aneg, -+ .config_init = rtl822xb_config_init, -+ .get_rate_matching = rtl822xb_get_rate_matching, -+ .read_status = rtl822xb_read_status, -+ .suspend = genphy_suspend, -+ .resume = rtlgen_resume, -+ .read_page = rtl821x_read_page, -+ .write_page = rtl821x_write_page, -+ }, { -+ .match_phy_device = rtl8221b_vn_cg_c45_match_phy_device, -+ .name = "RTL8221B-VN-CG 2.5Gbps PHY (C45)", -+ .config_init = rtl822xb_config_init, -+ .get_rate_matching = rtl822xb_get_rate_matching, -+ .get_features = rtl822x_c45_get_features, -+ .config_aneg = rtl822x_c45_config_aneg, -+ .read_status = rtl822xb_c45_read_status, -+ .suspend = genphy_c45_pma_suspend, -+ .resume = rtlgen_c45_resume, -+ }, { -+ .match_phy_device = rtl8251b_c45_match_phy_device, -+ .name = "RTL8251B 5Gbps PHY", -+ .get_features = rtl822x_get_features, -+ .config_aneg = rtl822x_config_aneg, -+ .read_status = rtl822x_read_status, -+ .suspend = genphy_suspend, -+ .resume = rtlgen_resume, -+ .read_page = rtl821x_read_page, -+ .write_page = rtl821x_write_page, -+ }, { -+ .match_phy_device = rtl_internal_nbaset_match_phy_device, -+ .name = "Realtek Internal NBASE-T PHY", -+ .flags = PHY_IS_INTERNAL, -+ .get_features = rtl822x_get_features, -+ .config_aneg = rtl822x_config_aneg, -+ .read_status = rtl822x_read_status, -+ .suspend = genphy_suspend, -+ .resume = rtlgen_resume, -+ .read_page = rtl821x_read_page, -+ .write_page = rtl821x_write_page, -+ .read_mmd = rtl822x_read_mmd, -+ .write_mmd = rtl822x_write_mmd, -+ }, { -+ PHY_ID_MATCH_EXACT(0x001ccad0), -+ .name = "RTL8224 2.5Gbps PHY", -+ .get_features = rtl822x_c45_get_features, -+ .config_aneg = rtl822x_c45_config_aneg, -+ .read_status = rtl822x_c45_read_status, -+ .suspend = genphy_c45_pma_suspend, -+ .resume = rtlgen_c45_resume, -+ }, { -+ PHY_ID_MATCH_EXACT(0x001cc961), -+ .name = "RTL8366RB Gigabit Ethernet", -+ .config_init = &rtl8366rb_config_init, -+ /* These interrupts are handled by the irq controller -+ * embedded inside the RTL8366RB, they get unmasked when the -+ * irq is requested and ACKed by reading the status register, -+ * which is done by the irqchip code. -+ */ -+ .config_intr = genphy_no_config_intr, -+ .handle_interrupt = genphy_handle_interrupt_no_ack, -+ .suspend = genphy_suspend, -+ .resume = genphy_resume, -+ }, { -+ PHY_ID_MATCH_EXACT(0x001ccb00), -+ .name = "RTL9000AA_RTL9000AN Ethernet", -+ .features = PHY_BASIC_T1_FEATURES, -+ .config_init = rtl9000a_config_init, -+ .config_aneg = rtl9000a_config_aneg, -+ .read_status = rtl9000a_read_status, -+ .config_intr = rtl9000a_config_intr, -+ .handle_interrupt = rtl9000a_handle_interrupt, -+ .suspend = genphy_suspend, -+ .resume = genphy_resume, -+ .read_page = rtl821x_read_page, -+ .write_page = rtl821x_write_page, -+ }, { -+ PHY_ID_MATCH_EXACT(0x001cc942), -+ .name = "RTL8365MB-VC Gigabit Ethernet", -+ /* Interrupt handling analogous to RTL8366RB */ -+ .config_intr = genphy_no_config_intr, -+ .handle_interrupt = genphy_handle_interrupt_no_ack, -+ .suspend = genphy_suspend, -+ .resume = genphy_resume, -+ }, { -+ PHY_ID_MATCH_EXACT(0x001cc960), -+ .name = "RTL8366S Gigabit Ethernet", -+ .suspend = genphy_suspend, -+ .resume = genphy_resume, -+ .read_mmd = genphy_read_mmd_unsupported, -+ .write_mmd = genphy_write_mmd_unsupported, -+ }, -+}; -+ -+module_phy_driver(realtek_drvs); -+ -+static const struct mdio_device_id __maybe_unused realtek_tbl[] = { -+ { PHY_ID_MATCH_VENDOR(0x001cc800) }, -+ { } -+}; -+ -+MODULE_DEVICE_TABLE(mdio, realtek_tbl); diff --git a/target/linux/generic/backport-6.12/781-25-v6.14-net-phy-realtek-add-hwmon-support-for-temp-sensor-on.patch b/target/linux/generic/backport-6.12/781-25-v6.14-net-phy-realtek-add-hwmon-support-for-temp-sensor-on.patch deleted file mode 100644 index 7c1fe54267..0000000000 --- a/target/linux/generic/backport-6.12/781-25-v6.14-net-phy-realtek-add-hwmon-support-for-temp-sensor-on.patch +++ /dev/null @@ -1,180 +0,0 @@ -From 33700ca45b7d2e1655d4cad95e25671e8a94e2f0 Mon Sep 17 00:00:00 2001 -From: Heiner Kallweit -Date: Sat, 11 Jan 2025 21:51:24 +0100 -Subject: [PATCH] net: phy: realtek: add hwmon support for temp sensor on - RTL822x - -This adds hwmon support for the temperature sensor on RTL822x. -It's available on the standalone versions of the PHY's, and on -the integrated PHY's in RTL8125B/RTL8125D/RTL8126. - -Signed-off-by: Heiner Kallweit -Reviewed-by: Andrew Lunn -Link: https://patch.msgid.link/ad6bfe9f-6375-4a00-84b4-bfb38a21bd71@gmail.com -Signed-off-by: Jakub Kicinski ---- - drivers/net/phy/realtek/Kconfig | 6 ++ - drivers/net/phy/realtek/Makefile | 1 + - drivers/net/phy/realtek/realtek.h | 10 ++++ - drivers/net/phy/realtek/realtek_hwmon.c | 79 +++++++++++++++++++++++++ - drivers/net/phy/realtek/realtek_main.c | 12 ++++ - 5 files changed, 108 insertions(+) - create mode 100644 drivers/net/phy/realtek/realtek.h - create mode 100644 drivers/net/phy/realtek/realtek_hwmon.c - ---- a/drivers/net/phy/realtek/Kconfig -+++ b/drivers/net/phy/realtek/Kconfig -@@ -3,3 +3,9 @@ config REALTEK_PHY - tristate "Realtek PHYs" - help - Currently supports RTL821x/RTL822x and fast ethernet PHYs -+ -+config REALTEK_PHY_HWMON -+ def_bool REALTEK_PHY && HWMON -+ depends on !(REALTEK_PHY=y && HWMON=m) -+ help -+ Optional hwmon support for the temperature sensor ---- a/drivers/net/phy/realtek/Makefile -+++ b/drivers/net/phy/realtek/Makefile -@@ -1,3 +1,4 @@ - # SPDX-License-Identifier: GPL-2.0 - realtek-y += realtek_main.o -+realtek-$(CONFIG_REALTEK_PHY_HWMON) += realtek_hwmon.o - obj-$(CONFIG_REALTEK_PHY) += realtek.o ---- /dev/null -+++ b/drivers/net/phy/realtek/realtek.h -@@ -0,0 +1,10 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+ -+#ifndef REALTEK_H -+#define REALTEK_H -+ -+#include -+ -+int rtl822x_hwmon_init(struct phy_device *phydev); -+ -+#endif /* REALTEK_H */ ---- /dev/null -+++ b/drivers/net/phy/realtek/realtek_hwmon.c -@@ -0,0 +1,86 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * HWMON support for Realtek PHY's -+ * -+ * Author: Heiner Kallweit -+ */ -+ -+#include -+#include -+ -+#include "realtek.h" -+ -+#define RTL822X_VND2_TSALRM 0xa662 -+#define RTL822X_VND2_TSRR 0xbd84 -+#define RTL822X_VND2_TSSR 0xb54c -+ -+static umode_t rtl822x_hwmon_is_visible(const void *drvdata, -+ enum hwmon_sensor_types type, -+ u32 attr, int channel) -+{ -+ return 0444; -+} -+ -+static int rtl822x_hwmon_get_temp(int raw) -+{ -+ if (raw >= 512) -+ raw -= 1024; -+ -+ return 1000 * raw / 2; -+} -+ -+static int rtl822x_hwmon_read(struct device *dev, enum hwmon_sensor_types type, -+ u32 attr, int channel, long *val) -+{ -+ struct phy_device *phydev = dev_get_drvdata(dev); -+ int raw; -+ -+ switch (attr) { -+ case hwmon_temp_input: -+ raw = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_TSRR) & 0x3ff; -+ *val = rtl822x_hwmon_get_temp(raw); -+ break; -+ case hwmon_temp_max: -+ /* Chip reduces speed to 1G if threshold is exceeded */ -+ raw = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_TSSR) >> 6; -+ *val = rtl822x_hwmon_get_temp(raw); -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static const struct hwmon_ops rtl822x_hwmon_ops = { -+ .is_visible = rtl822x_hwmon_is_visible, -+ .read = rtl822x_hwmon_read, -+}; -+ -+static const struct hwmon_channel_info * const rtl822x_hwmon_info[] = { -+ HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX), -+ NULL -+}; -+ -+static const struct hwmon_chip_info rtl822x_hwmon_chip_info = { -+ .ops = &rtl822x_hwmon_ops, -+ .info = rtl822x_hwmon_info, -+}; -+ -+int rtl822x_hwmon_init(struct phy_device *phydev) -+{ -+ struct device *hwdev, *dev = &phydev->mdio.dev; -+ const char *name; -+ -+ /* Ensure over-temp alarm is reset. */ -+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_TSALRM, 3); -+ -+ name = devm_hwmon_sanitize_name(dev, dev_name(dev)); -+ if (IS_ERR(name)) -+ return PTR_ERR(name); -+ -+ hwdev = devm_hwmon_device_register_with_info(dev, name, phydev, -+ &rtl822x_hwmon_chip_info, -+ NULL); -+ return PTR_ERR_OR_ZERO(hwdev); -+} ---- a/drivers/net/phy/realtek/realtek_main.c -+++ b/drivers/net/phy/realtek/realtek_main.c -@@ -14,6 +14,8 @@ - #include - #include - -+#include "realtek.h" -+ - #define RTL821x_PHYSR 0x11 - #define RTL821x_PHYSR_DUPLEX BIT(13) - #define RTL821x_PHYSR_SPEED GENMASK(15, 14) -@@ -820,6 +822,15 @@ static int rtl822x_write_mmd(struct phy_ - return ret; - } - -+static int rtl822x_probe(struct phy_device *phydev) -+{ -+ if (IS_ENABLED(CONFIG_REALTEK_PHY_HWMON) && -+ phydev->phy_id != RTL_GENERIC_PHYID) -+ return rtl822x_hwmon_init(phydev); -+ -+ return 0; -+} -+ - static int rtl822xb_config_init(struct phy_device *phydev) - { - bool has_2500, has_sgmii; -@@ -1518,6 +1529,7 @@ static struct phy_driver realtek_drvs[] - .match_phy_device = rtl_internal_nbaset_match_phy_device, - .name = "Realtek Internal NBASE-T PHY", - .flags = PHY_IS_INTERNAL, -+ .probe = rtl822x_probe, - .get_features = rtl822x_get_features, - .config_aneg = rtl822x_config_aneg, - .read_status = rtl822x_read_status, diff --git a/target/linux/generic/backport-6.12/781-26-v6.14-net-phy-realtek-HWMON-support-for-standalone-version.patch b/target/linux/generic/backport-6.12/781-26-v6.14-net-phy-realtek-HWMON-support-for-standalone-version.patch deleted file mode 100644 index 8b8c97c54f..0000000000 --- a/target/linux/generic/backport-6.12/781-26-v6.14-net-phy-realtek-HWMON-support-for-standalone-version.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 64ff63aeefb03139ae27454bd4208244579ae88e Mon Sep 17 00:00:00 2001 -From: Aleksander Jan Bajkowski -Date: Fri, 17 Jan 2025 23:24:21 +0100 -Subject: [PATCH] net: phy: realtek: HWMON support for standalone versions of - RTL8221B and RTL8251 - -HWMON support has been added for the RTL8221/8251 PHYs integrated together -with the MAC inside the RTL8125/8126 chips. This patch extends temperature -reading support for standalone variants of the mentioned PHYs. - -I don't know whether the earlier revisions of the RTL8226 also have a -built-in temperature sensor, so they have been skipped for now. - -Tested on RTL8221B-VB-CG. - -Signed-off-by: Aleksander Jan Bajkowski -Reviewed-by: Andrew Lunn -Signed-off-by: David S. Miller ---- - drivers/net/phy/realtek/realtek_main.c | 5 +++++ - 1 file changed, 5 insertions(+) - ---- a/drivers/net/phy/realtek/realtek_main.c -+++ b/drivers/net/phy/realtek/realtek_main.c -@@ -1474,6 +1474,7 @@ static struct phy_driver realtek_drvs[] - }, { - .match_phy_device = rtl8221b_vb_cg_c22_match_phy_device, - .name = "RTL8221B-VB-CG 2.5Gbps PHY (C22)", -+ .probe = rtl822x_probe, - .get_features = rtl822x_get_features, - .config_aneg = rtl822x_config_aneg, - .config_init = rtl822xb_config_init, -@@ -1486,6 +1487,7 @@ static struct phy_driver realtek_drvs[] - }, { - .match_phy_device = rtl8221b_vb_cg_c45_match_phy_device, - .name = "RTL8221B-VB-CG 2.5Gbps PHY (C45)", -+ .probe = rtl822x_probe, - .config_init = rtl822xb_config_init, - .get_rate_matching = rtl822xb_get_rate_matching, - .get_features = rtl822x_c45_get_features, -@@ -1496,6 +1498,7 @@ static struct phy_driver realtek_drvs[] - }, { - .match_phy_device = rtl8221b_vn_cg_c22_match_phy_device, - .name = "RTL8221B-VM-CG 2.5Gbps PHY (C22)", -+ .probe = rtl822x_probe, - .get_features = rtl822x_get_features, - .config_aneg = rtl822x_config_aneg, - .config_init = rtl822xb_config_init, -@@ -1508,6 +1511,7 @@ static struct phy_driver realtek_drvs[] - }, { - .match_phy_device = rtl8221b_vn_cg_c45_match_phy_device, - .name = "RTL8221B-VN-CG 2.5Gbps PHY (C45)", -+ .probe = rtl822x_probe, - .config_init = rtl822xb_config_init, - .get_rate_matching = rtl822xb_get_rate_matching, - .get_features = rtl822x_c45_get_features, -@@ -1518,6 +1522,7 @@ static struct phy_driver realtek_drvs[] - }, { - .match_phy_device = rtl8251b_c45_match_phy_device, - .name = "RTL8251B 5Gbps PHY", -+ .probe = rtl822x_probe, - .get_features = rtl822x_get_features, - .config_aneg = rtl822x_config_aneg, - .read_status = rtl822x_read_status, diff --git a/target/linux/generic/backport-6.12/781-27-v6.15-net-phy-realtek-make-HWMON-support-a-user-visible-Kc.patch b/target/linux/generic/backport-6.12/781-27-v6.15-net-phy-realtek-make-HWMON-support-a-user-visible-Kc.patch deleted file mode 100644 index 821d7ee879..0000000000 --- a/target/linux/generic/backport-6.12/781-27-v6.15-net-phy-realtek-make-HWMON-support-a-user-visible-Kc.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 51773846fab24a353bed4ebb660997ced4bc32d7 Mon Sep 17 00:00:00 2001 -From: Heiner Kallweit -Date: Mon, 3 Feb 2025 21:33:39 +0100 -Subject: [PATCH] net: phy: realtek: make HWMON support a user-visible Kconfig - symbol - -Make config symbol REALTEK_PHY_HWMON user-visible, so that users can -remove support if not needed. - -Suggested-by: Geert Uytterhoeven -Signed-off-by: Heiner Kallweit -Reviewed-by: Simon Horman -Link: https://patch.msgid.link/3466ee92-166a-4b0f-9ae7-42b9e046f333@gmail.com -Signed-off-by: Jakub Kicinski ---- - drivers/net/phy/realtek/Kconfig | 8 ++++++-- - 1 file changed, 6 insertions(+), 2 deletions(-) - ---- a/drivers/net/phy/realtek/Kconfig -+++ b/drivers/net/phy/realtek/Kconfig -@@ -4,8 +4,12 @@ config REALTEK_PHY - help - Currently supports RTL821x/RTL822x and fast ethernet PHYs - -+if REALTEK_PHY -+ - config REALTEK_PHY_HWMON -- def_bool REALTEK_PHY && HWMON -- depends on !(REALTEK_PHY=y && HWMON=m) -+ bool "HWMON support for Realtek PHYs" -+ depends on HWMON && !(REALTEK_PHY=y && HWMON=m) - help - Optional hwmon support for the temperature sensor -+ -+endif # REALTEK_PHY diff --git a/target/linux/generic/backport-6.12/781-28-v6.15-net-phy-realtek-use-string-choices-helpers.patch b/target/linux/generic/backport-6.12/781-28-v6.15-net-phy-realtek-use-string-choices-helpers.patch deleted file mode 100644 index d3e09bc7cd..0000000000 --- a/target/linux/generic/backport-6.12/781-28-v6.15-net-phy-realtek-use-string-choices-helpers.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 0bea93fdbaf8675b7e8124bdcaf51497dcc8bcfa Mon Sep 17 00:00:00 2001 -From: Heiner Kallweit -Date: Mon, 3 Feb 2025 21:41:36 +0100 -Subject: [PATCH] net: phy: realtek: use string choices helpers - -Use string choices helpers to simplify the code. - -Reported-by: kernel test robot -Closes: https://lore.kernel.org/oe-kbuild-all/202501190707.qQS8PGHW-lkp@intel.com/ -Signed-off-by: Heiner Kallweit -Reviewed-by: Simon Horman -Signed-off-by: David S. Miller ---- - drivers/net/phy/realtek/realtek_main.c | 9 +++++---- - 1 file changed, 5 insertions(+), 4 deletions(-) - ---- a/drivers/net/phy/realtek/realtek_main.c -+++ b/drivers/net/phy/realtek/realtek_main.c -@@ -13,6 +13,7 @@ - #include - #include - #include -+#include - - #include "realtek.h" - -@@ -422,11 +423,11 @@ static int rtl8211f_config_init(struct p - } else if (ret) { - dev_dbg(dev, - "%s 2ns TX delay (and changing the value from pin-strapping RXD1 or the bootloader)\n", -- val_txdly ? "Enabling" : "Disabling"); -+ str_enable_disable(val_txdly)); - } else { - dev_dbg(dev, - "2ns TX delay was already %s (by pin-strapping RXD1 or bootloader configuration)\n", -- val_txdly ? "enabled" : "disabled"); -+ str_enabled_disabled(val_txdly)); - } - - ret = phy_modify_paged_changed(phydev, 0xd08, 0x15, RTL8211F_RX_DELAY, -@@ -437,11 +438,11 @@ static int rtl8211f_config_init(struct p - } else if (ret) { - dev_dbg(dev, - "%s 2ns RX delay (and changing the value from pin-strapping RXD0 or the bootloader)\n", -- val_rxdly ? "Enabling" : "Disabling"); -+ str_enable_disable(val_rxdly)); - } else { - dev_dbg(dev, - "2ns RX delay was already %s (by pin-strapping RXD0 or bootloader configuration)\n", -- val_rxdly ? "enabled" : "disabled"); -+ str_enabled_disabled(val_rxdly)); - } - - if (priv->has_phycr2) { diff --git a/target/linux/generic/backport-6.12/781-29-v6.15-net-phy-realtek-improve-mmd-register-access-for-inte.patch b/target/linux/generic/backport-6.12/781-29-v6.15-net-phy-realtek-improve-mmd-register-access-for-inte.patch deleted file mode 100644 index 3a3a20d58b..0000000000 --- a/target/linux/generic/backport-6.12/781-29-v6.15-net-phy-realtek-improve-mmd-register-access-for-inte.patch +++ /dev/null @@ -1,134 +0,0 @@ -From da681ed73fb980286fc29de707b35d76bb33e123 Mon Sep 17 00:00:00 2001 -From: Heiner Kallweit -Date: Thu, 13 Feb 2025 20:18:17 +0100 -Subject: [PATCH] net: phy: realtek: improve mmd register access for internal - PHY's - -r8169 provides the MDIO bus for the internal PHY's. It has been extended -with c45 access functions for addressing MDIO_MMD_VEND2 registers. -So we can switch from paged access to directly addressing the -MDIO_MMD_VEND2 registers. - -Signed-off-by: Heiner Kallweit -Reviewed-by: Andrew Lunn -Link: https://patch.msgid.link/a5f2333c-dda9-48ad-9801-77049766e632@gmail.com -Signed-off-by: Jakub Kicinski ---- - drivers/net/phy/realtek/realtek_main.c | 79 +++++++++++--------------- - 1 file changed, 33 insertions(+), 46 deletions(-) - ---- a/drivers/net/phy/realtek/realtek_main.c -+++ b/drivers/net/phy/realtek/realtek_main.c -@@ -735,29 +735,31 @@ static int rtlgen_read_status(struct phy - return 0; - } - -+static int rtlgen_read_vend2(struct phy_device *phydev, int regnum) -+{ -+ return __mdiobus_c45_read(phydev->mdio.bus, 0, MDIO_MMD_VEND2, regnum); -+} -+ -+static int rtlgen_write_vend2(struct phy_device *phydev, int regnum, u16 val) -+{ -+ return __mdiobus_c45_write(phydev->mdio.bus, 0, MDIO_MMD_VEND2, regnum, -+ val); -+} -+ - static int rtlgen_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) - { - int ret; - -- if (devnum == MDIO_MMD_VEND2) { -- rtl821x_write_page(phydev, regnum >> 4); -- ret = __phy_read(phydev, 0x10 + ((regnum & 0xf) >> 1)); -- rtl821x_write_page(phydev, 0); -- } else if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) { -- rtl821x_write_page(phydev, 0xa5c); -- ret = __phy_read(phydev, 0x12); -- rtl821x_write_page(phydev, 0); -- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) { -- rtl821x_write_page(phydev, 0xa5d); -- ret = __phy_read(phydev, 0x10); -- rtl821x_write_page(phydev, 0); -- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE) { -- rtl821x_write_page(phydev, 0xa5d); -- ret = __phy_read(phydev, 0x11); -- rtl821x_write_page(phydev, 0); -- } else { -+ if (devnum == MDIO_MMD_VEND2) -+ ret = rtlgen_read_vend2(phydev, regnum); -+ else if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) -+ ret = rtlgen_read_vend2(phydev, 0xa5c4); -+ else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) -+ ret = rtlgen_read_vend2(phydev, 0xa5d0); -+ else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE) -+ ret = rtlgen_read_vend2(phydev, 0xa5d2); -+ else - ret = -EOPNOTSUPP; -- } - - return ret; - } -@@ -767,17 +769,12 @@ static int rtlgen_write_mmd(struct phy_d - { - int ret; - -- if (devnum == MDIO_MMD_VEND2) { -- rtl821x_write_page(phydev, regnum >> 4); -- ret = __phy_write(phydev, 0x10 + ((regnum & 0xf) >> 1), val); -- rtl821x_write_page(phydev, 0); -- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) { -- rtl821x_write_page(phydev, 0xa5d); -- ret = __phy_write(phydev, 0x10, val); -- rtl821x_write_page(phydev, 0); -- } else { -+ if (devnum == MDIO_MMD_VEND2) -+ ret = rtlgen_write_vend2(phydev, regnum, val); -+ else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) -+ ret = rtlgen_write_vend2(phydev, regnum, 0xa5d0); -+ else - ret = -EOPNOTSUPP; -- } - - return ret; - } -@@ -789,19 +786,12 @@ static int rtl822x_read_mmd(struct phy_d - if (ret != -EOPNOTSUPP) - return ret; - -- if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE2) { -- rtl821x_write_page(phydev, 0xa6e); -- ret = __phy_read(phydev, 0x16); -- rtl821x_write_page(phydev, 0); -- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) { -- rtl821x_write_page(phydev, 0xa6d); -- ret = __phy_read(phydev, 0x12); -- rtl821x_write_page(phydev, 0); -- } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE2) { -- rtl821x_write_page(phydev, 0xa6d); -- ret = __phy_read(phydev, 0x10); -- rtl821x_write_page(phydev, 0); -- } -+ if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE2) -+ ret = rtlgen_read_vend2(phydev, 0xa6ec); -+ else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) -+ ret = rtlgen_read_vend2(phydev, 0xa6d4); -+ else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE2) -+ ret = rtlgen_read_vend2(phydev, 0xa6d0); - - return ret; - } -@@ -814,11 +804,8 @@ static int rtl822x_write_mmd(struct phy_ - if (ret != -EOPNOTSUPP) - return ret; - -- if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) { -- rtl821x_write_page(phydev, 0xa6d); -- ret = __phy_write(phydev, 0x12, val); -- rtl821x_write_page(phydev, 0); -- } -+ if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) -+ ret = rtlgen_write_vend2(phydev, 0xa6d4, val); - - return ret; - } diff --git a/target/linux/generic/backport-6.12/781-30-v6.15-net-phy-realtek-switch-from-paged-to-MMD-ops-in-rtl8.patch b/target/linux/generic/backport-6.12/781-30-v6.15-net-phy-realtek-switch-from-paged-to-MMD-ops-in-rtl8.patch deleted file mode 100644 index 5e3c3ce70a..0000000000 --- a/target/linux/generic/backport-6.12/781-30-v6.15-net-phy-realtek-switch-from-paged-to-MMD-ops-in-rtl8.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 02d3b306ac2f0b174753d1c5b9e4e5fb8ec5057e Mon Sep 17 00:00:00 2001 -From: Heiner Kallweit -Date: Thu, 13 Feb 2025 20:19:14 +0100 -Subject: [PATCH] net: phy: realtek: switch from paged to MMD ops in rtl822x - functions - -The MDIO bus provided by r8169 for the internal PHY's now supports -c45 ops for the MDIO_MMD_VEND2 device. So we can switch to standard -MMD ops here. - -Signed-off-by: Heiner Kallweit -Reviewed-by: Andrew Lunn -Link: https://patch.msgid.link/81416f95-0fac-4225-87b4-828e3738b8ed@gmail.com -Signed-off-by: Jakub Kicinski ---- - drivers/net/phy/realtek/realtek_main.c | 11 +++++------ - 1 file changed, 5 insertions(+), 6 deletions(-) - ---- a/drivers/net/phy/realtek/realtek_main.c -+++ b/drivers/net/phy/realtek/realtek_main.c -@@ -901,7 +901,7 @@ static int rtl822x_get_features(struct p - { - int val; - -- val = phy_read_paged(phydev, 0xa61, 0x13); -+ val = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xa616); - if (val < 0) - return val; - -@@ -922,10 +922,9 @@ static int rtl822x_config_aneg(struct ph - if (phydev->autoneg == AUTONEG_ENABLE) { - u16 adv = linkmode_adv_to_mii_10gbt_adv_t(phydev->advertising); - -- ret = phy_modify_paged_changed(phydev, 0xa5d, 0x12, -- MDIO_AN_10GBT_CTRL_ADV2_5G | -- MDIO_AN_10GBT_CTRL_ADV5G, -- adv); -+ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, 0xa5d4, -+ MDIO_AN_10GBT_CTRL_ADV2_5G | -+ MDIO_AN_10GBT_CTRL_ADV5G, adv); - if (ret < 0) - return ret; - } -@@ -969,7 +968,7 @@ static int rtl822x_read_status(struct ph - !phydev->autoneg_complete) - return 0; - -- lpadv = phy_read_paged(phydev, 0xa5d, 0x13); -+ lpadv = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xa5d6); - if (lpadv < 0) - return lpadv; - diff --git a/target/linux/generic/backport-6.12/781-31-v6.15-net-phy-realtek-add-helper-RTL822X_VND2_C22_REG.patch b/target/linux/generic/backport-6.12/781-31-v6.15-net-phy-realtek-add-helper-RTL822X_VND2_C22_REG.patch deleted file mode 100644 index 5134d08b1c..0000000000 --- a/target/linux/generic/backport-6.12/781-31-v6.15-net-phy-realtek-add-helper-RTL822X_VND2_C22_REG.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 8af2136e77989a64fae0284bf76fd584e32edd3a Mon Sep 17 00:00:00 2001 -From: Heiner Kallweit -Date: Fri, 14 Feb 2025 21:31:14 +0100 -Subject: [PATCH] net: phy: realtek: add helper RTL822X_VND2_C22_REG - -C22 register space is mapped to 0xa400 in MMD VEND2 register space. -Add a helper to access mapped C22 registers. - -Signed-off-by: Heiner Kallweit -Reviewed-by: Andrew Lunn -Link: https://patch.msgid.link/6344277b-c5c7-449b-ac89-d5425306ca76@gmail.com -Signed-off-by: Jakub Kicinski ---- - drivers/net/phy/realtek/realtek_main.c | 9 ++++----- - 1 file changed, 4 insertions(+), 5 deletions(-) - ---- a/drivers/net/phy/realtek/realtek_main.c -+++ b/drivers/net/phy/realtek/realtek_main.c -@@ -79,9 +79,7 @@ - /* RTL822X_VND2_XXXXX registers are only accessible when phydev->is_c45 - * is set, they cannot be accessed by C45-over-C22. - */ --#define RTL822X_VND2_GBCR 0xa412 -- --#define RTL822X_VND2_GANLPAR 0xa414 -+#define RTL822X_VND2_C22_REG(reg) (0xa400 + 2 * (reg)) - - #define RTL8366RB_POWER_SAVE 0x15 - #define RTL8366RB_POWER_SAVE_ON BIT(12) -@@ -1015,7 +1013,8 @@ static int rtl822x_c45_config_aneg(struc - val = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising); - - /* Vendor register as C45 has no standardized support for 1000BaseT */ -- ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, RTL822X_VND2_GBCR, -+ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, -+ RTL822X_VND2_C22_REG(MII_CTRL1000), - ADVERTISE_1000FULL, val); - if (ret < 0) - return ret; -@@ -1032,7 +1031,7 @@ static int rtl822x_c45_read_status(struc - /* Vendor register as C45 has no standardized support for 1000BaseT */ - if (phydev->autoneg == AUTONEG_ENABLE && genphy_c45_aneg_done(phydev)) { - val = phy_read_mmd(phydev, MDIO_MMD_VEND2, -- RTL822X_VND2_GANLPAR); -+ RTL822X_VND2_C22_REG(MII_STAT1000)); - if (val < 0) - return val; - } else { diff --git a/target/linux/generic/backport-6.12/781-32-v6.15-net-phy-realtek-add-defines-for-shadowed-c45-standar.patch b/target/linux/generic/backport-6.12/781-32-v6.15-net-phy-realtek-add-defines-for-shadowed-c45-standar.patch deleted file mode 100644 index ff7d5b1fb6..0000000000 --- a/target/linux/generic/backport-6.12/781-32-v6.15-net-phy-realtek-add-defines-for-shadowed-c45-standar.patch +++ /dev/null @@ -1,113 +0,0 @@ -From fabcfd6d10999024a721ae1b965b57eb8a305ace Mon Sep 17 00:00:00 2001 -From: Heiner Kallweit -Date: Sat, 15 Feb 2025 14:29:15 +0100 -Subject: [PATCH] net: phy: realtek: add defines for shadowed c45 standard - registers - -Realtek shadows standard c45 registers in VEND2 device register space. -Add defines for these VEND2 registers, based on the names of the -standard c45 registers. - -Signed-off-by: Heiner Kallweit -Reviewed-by: Andrew Lunn -Link: https://patch.msgid.link/c90bdf76-f8b8-4d06-9656-7a52d5658ee6@gmail.com -Signed-off-by: Jakub Kicinski ---- - drivers/net/phy/realtek/realtek_main.c | 33 +++++++++++++++++--------- - 1 file changed, 22 insertions(+), 11 deletions(-) - ---- a/drivers/net/phy/realtek/realtek_main.c -+++ b/drivers/net/phy/realtek/realtek_main.c -@@ -94,6 +94,16 @@ - #define RTL_VND2_PHYSR_MASTER BIT(11) - #define RTL_VND2_PHYSR_SPEED_MASK (RTL_VND2_PHYSR_SPEEDL | RTL_VND2_PHYSR_SPEEDH) - -+#define RTL_MDIO_PCS_EEE_ABLE 0xa5c4 -+#define RTL_MDIO_AN_EEE_ADV 0xa5d0 -+#define RTL_MDIO_AN_EEE_LPABLE 0xa5d2 -+#define RTL_MDIO_AN_10GBT_CTRL 0xa5d4 -+#define RTL_MDIO_AN_10GBT_STAT 0xa5d6 -+#define RTL_MDIO_PMA_SPEED 0xa616 -+#define RTL_MDIO_AN_EEE_LPABLE2 0xa6d0 -+#define RTL_MDIO_AN_EEE_ADV2 0xa6d4 -+#define RTL_MDIO_PCS_EEE_ABLE2 0xa6ec -+ - #define RTL_GENERIC_PHYID 0x001cc800 - #define RTL_8211FVD_PHYID 0x001cc878 - #define RTL_8221B 0x001cc840 -@@ -751,11 +761,11 @@ static int rtlgen_read_mmd(struct phy_de - if (devnum == MDIO_MMD_VEND2) - ret = rtlgen_read_vend2(phydev, regnum); - else if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) -- ret = rtlgen_read_vend2(phydev, 0xa5c4); -+ ret = rtlgen_read_vend2(phydev, RTL_MDIO_PCS_EEE_ABLE); - else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) -- ret = rtlgen_read_vend2(phydev, 0xa5d0); -+ ret = rtlgen_read_vend2(phydev, RTL_MDIO_AN_EEE_ADV); - else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE) -- ret = rtlgen_read_vend2(phydev, 0xa5d2); -+ ret = rtlgen_read_vend2(phydev, RTL_MDIO_AN_EEE_LPABLE); - else - ret = -EOPNOTSUPP; - -@@ -770,7 +780,7 @@ static int rtlgen_write_mmd(struct phy_d - if (devnum == MDIO_MMD_VEND2) - ret = rtlgen_write_vend2(phydev, regnum, val); - else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) -- ret = rtlgen_write_vend2(phydev, regnum, 0xa5d0); -+ ret = rtlgen_write_vend2(phydev, regnum, RTL_MDIO_AN_EEE_ADV); - else - ret = -EOPNOTSUPP; - -@@ -785,11 +795,11 @@ static int rtl822x_read_mmd(struct phy_d - return ret; - - if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE2) -- ret = rtlgen_read_vend2(phydev, 0xa6ec); -+ ret = rtlgen_read_vend2(phydev, RTL_MDIO_PCS_EEE_ABLE2); - else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) -- ret = rtlgen_read_vend2(phydev, 0xa6d4); -+ ret = rtlgen_read_vend2(phydev, RTL_MDIO_AN_EEE_ADV2); - else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE2) -- ret = rtlgen_read_vend2(phydev, 0xa6d0); -+ ret = rtlgen_read_vend2(phydev, RTL_MDIO_AN_EEE_LPABLE2); - - return ret; - } -@@ -803,7 +813,7 @@ static int rtl822x_write_mmd(struct phy_ - return ret; - - if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) -- ret = rtlgen_write_vend2(phydev, 0xa6d4, val); -+ ret = rtlgen_write_vend2(phydev, RTL_MDIO_AN_EEE_ADV2, val); - - return ret; - } -@@ -899,7 +909,7 @@ static int rtl822x_get_features(struct p - { - int val; - -- val = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xa616); -+ val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL_MDIO_PMA_SPEED); - if (val < 0) - return val; - -@@ -920,7 +930,8 @@ static int rtl822x_config_aneg(struct ph - if (phydev->autoneg == AUTONEG_ENABLE) { - u16 adv = linkmode_adv_to_mii_10gbt_adv_t(phydev->advertising); - -- ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, 0xa5d4, -+ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, -+ RTL_MDIO_AN_10GBT_CTRL, - MDIO_AN_10GBT_CTRL_ADV2_5G | - MDIO_AN_10GBT_CTRL_ADV5G, adv); - if (ret < 0) -@@ -966,7 +977,7 @@ static int rtl822x_read_status(struct ph - !phydev->autoneg_complete) - return 0; - -- lpadv = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xa5d6); -+ lpadv = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL_MDIO_AN_10GBT_STAT); - if (lpadv < 0) - return lpadv; - diff --git a/target/linux/generic/backport-6.12/781-33-v6.15-net-phy-realtek-disable-PHY-mode-EEE.patch b/target/linux/generic/backport-6.12/781-33-v6.15-net-phy-realtek-disable-PHY-mode-EEE.patch deleted file mode 100644 index 4d755d4e22..0000000000 --- a/target/linux/generic/backport-6.12/781-33-v6.15-net-phy-realtek-disable-PHY-mode-EEE.patch +++ /dev/null @@ -1,54 +0,0 @@ -From bfc17c1658353f22843c7c13e27c2d31950f1887 Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Sun, 16 Mar 2025 12:39:54 +0000 -Subject: [PATCH] net: phy: realtek: disable PHY-mode EEE - -Realtek RTL8211F has a "PHY-mode" EEE support which interferes with an -IEEE 802.3 compliant implementation. This mode defaults to enabled, and -results in the MAC receive path not seeing the link transition to LPI -state. - -Fix this by disabling PHY-mode EEE. - -Signed-off-by: Russell King (Oracle) -Reviewed-by: Andrew Lunn -Link: https://patch.msgid.link/E1ttnHW-00785s-Uq@rmk-PC.armlinux.org.uk -Signed-off-by: Paolo Abeni ---- - drivers/net/phy/realtek/realtek_main.c | 11 +++++++++-- - 1 file changed, 9 insertions(+), 2 deletions(-) - ---- a/drivers/net/phy/realtek/realtek_main.c -+++ b/drivers/net/phy/realtek/realtek_main.c -@@ -33,6 +33,9 @@ - - #define RTL8211F_PHYCR1 0x18 - #define RTL8211F_PHYCR2 0x19 -+#define RTL8211F_CLKOUT_EN BIT(0) -+#define RTL8211F_PHYCR2_PHY_EEE_ENABLE BIT(5) -+ - #define RTL8211F_INSR 0x1d - - #define RTL8211F_LEDCR 0x10 -@@ -55,8 +58,6 @@ - #define RTL8211E_TX_DELAY BIT(12) - #define RTL8211E_RX_DELAY BIT(11) - --#define RTL8211F_CLKOUT_EN BIT(0) -- - #define RTL8201F_ISR 0x1e - #define RTL8201F_ISR_ANERR BIT(15) - #define RTL8201F_ISR_DUPLEX BIT(13) -@@ -453,6 +454,12 @@ static int rtl8211f_config_init(struct p - str_enabled_disabled(val_rxdly)); - } - -+ /* Disable PHY-mode EEE so LPI is passed to the MAC */ -+ ret = phy_modify_paged(phydev, 0xa43, RTL8211F_PHYCR2, -+ RTL8211F_PHYCR2_PHY_EEE_ENABLE, 0); -+ if (ret) -+ return ret; -+ - if (priv->has_phycr2) { - ret = phy_modify_paged(phydev, 0xa43, RTL8211F_PHYCR2, - RTL8211F_CLKOUT_EN, priv->phycr2);